C++ IO流的概念及流類庫、檔案操作
阿新 • • 發佈:2019-01-31
IO流的概念及流類庫
當程式與外界進行資訊交換時,存在兩個物件,一個是程式中的物件,另一個是檔案物件。
流是資訊流動的一種抽象,它負責在資料的生產者和資料的消費者之間建立聯絡,並管理資料的流動
流物件與檔案操作
- 程式建立一個流物件
- 指定這個流物件與某個檔案物件建立連線
- 程式操作流物件
- 流物件通過檔案系統對所連線的檔案物件產生作用
提取與插入
- 讀操作在流資料抽象中被稱為(從流中)提取
- 寫造作被稱為(向流中)插入
輸出流概述
C++中有三個重要的輸出流
ostream
ofstream
ostringstream
預先定義的三個輸出流物件
cout
標準輸出cerr
標準錯誤輸出,沒有緩衝,傳送給他的內容立即輸出clog
類似於cerr
,但是有緩衝,緩衝區滿時被輸出
標準輸出換向
ofstream fout("b.out");
streambuf* pOld=cout.rdbuf(fout.rdbuf());
//···
cout.rdbuf(pOld);
構造輸出流物件
ofstream
類支援磁碟檔案輸出- 如果在建構函式中指定一個檔名,當構造這個檔案時該檔案是自動開啟的
ofstream myfile(filename");
- 可以在呼叫預設建構函式之後使用
open
成員函式開啟檔案
ofstream myfile;
宣告一個靜態檔案輸出流物件myfile.open(" filename")
開啟檔案,使流物件與檔案建立聯絡
-在構造物件或用open
開啟檔案時可以指定模式
-ofstream myfile("filename", ios. base out | ios base:binary);
檔案輸出流成員函式的三種類型
- 與操作符等價的成員函式
- 執行非格式化寫操作的成員函式
- 其它修改流狀態且不同於操作符或插入運算子的成員函式
檔案輸出流成員函式
open
函式
- 把流與一個特定的磁碟檔案關聯起來
- 需要指定開啟模式。
put
函式
- 把一個字元寫到輸出流中
writer
函式
- 將記憶體中的一塊內容寫到一個檔案輸出流中
seekp
和tellp
函式
- 操作檔案流的內部指標
close
函式
- 關閉與個檔案輸出流關聯的磁碟檔案
- 錯誤處理函式
- 在寫到一個流時進行錯誤處理
向文字檔案輸出
插入(<<)運算子
- 為所有標準
c++
資料型別預先設計的,用於傳送位元組到一個輸出流物件操縱符(
manipulator
)
- 插入運算子與操縱符一起工作
- 輸出格式控制
- 很多操縱符都定義在
ios_base
類中(如hex()
)、<iomanip>
標頭檔案(如setprecision()
)- 控制輸出寬度
- 在流中放入
setw
操縱符或呼叫width成員函式為每個項指定輸出寬度setw
和width
僅影響緊隨其後的輸出項,但其它流格式操縱符是持久的,保持有效直到發生改變dec
、oct
和hex
操縱符設定輸入和輸出的預設進位制
例子:使用wisth
控制輸出寬度
#include <iostream>
using namespace std;
int main(void)
{
double values[] = { 1.23,35.36,653.7,4358.24 };
for (int i = 0; i < 4; i++) {
cout.width(10);
cout << values[i] << endl;
}
return 0;
}
程式執行結果:沒有指定對齊方式採用預設對齊方式輸出
1.23
35.36
653.7
4358.24
請按任意鍵繼續. . .
同樣的例子用操縱符實現:注意包含相應標頭檔案
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(void)
{
double values[] = { 1.23,35.36,653.7,4358.24 };
string names[] = { "Zoot","Jimmy","AI","Stan" };
for (int i = 0; i < 4; i++) {
cout << setw(6)<<names[i] <<setw(10)<<values[i]<< endl;
}
return 0;
}
程式執行結果:
Zoot 1.23
Jimmy 35.36
AI 653.7
Stan 4358.24
請按任意鍵繼續. . .
控制對齊方式
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(void)
{
double values[] = { 1.23,35.36,653.7,4358.24 };
string names[] = { "Zoot","Jimmy","AI","Stan" };
for (int i = 0; i < 4; i++) {
cout << setiosflags(ios_base::left)
<<setw(6)
<<names[i]
<<resetiosflags(ios_base::left)
<<setw(10)
<<values[i]<< endl;
}
return 0;
}
程式執行結果:
Zoot 1.23
Jimmy 35.36
AI 653.7
Stan 4358.24
請按任意鍵繼續. . .
setiosflags
操縱符
- 這個程式中,通過使用帶引數的
setiosflags
操縱符來設定左對齊,setiosflags
定義在標頭檔案iomanip
中- 引數
ios_base::left
是ios_base
靜態常量,因此引用時必須包括ios_base::
字首。- 這裡需要用
resetiosflags
操縱符關閉左對齊標誌。setiosflags
不同於width
和setw
,它的影響是持久的,直到resetiosflags
重新恢復預設為止setiosflags
的引數是該流的格式標誌值,可用按位或(|
)運算子進行組合
精度
- 浮點數輸出精度預設值是
6
,例如:3466.98
- 要改變精度:
setprecision
操作符(定義在iomanip
中)- 如果不指定
fixed
或scientific
,精度值表示有效數字位數- 如果設定了
ios_base::fixed
或ios_base::scientific
精度值表示小數點之後的位數
控制輸出精度例子(不設定fixed或scientific)
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(void)
{
double values[] = { 1.23,35.36,653.7,4358.24 };
string names[] = { "Zoot","Jimmy","AI","Stan" };
for (int i = 0; i < 4; i++) {
cout << setiosflags(ios_base::left)
<< setw(6)
<< names[i]
<<resetiosflags(ios_base::right)
<<setw(10)
<<setprecision(1)<<values[i]<<endl;
}
return 0;
}
程式執行效果:
Zoot 1
Jimmy 4e+01
AI 7e+02
Stan 4e+03
請按任意鍵繼續. . .
控制輸出精度例子(設定fixed,setprecision表示小數點後幾位)
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(void)
{
double values[] = { 1.23,35.36,653.7,4358.24 };
string names[] = { "Zoot","Jimmy","AI","Stan" };
cout << setiosflags(ios_base::fixed); //設定
for (int i = 0; i < 4; i++) {
cout << setiosflags(ios_base::left)
<< setw(6)
<< names[i]
<<resetiosflags(ios_base::right)
<<setw(10)
<<setprecision(1)<<values[i]<<endl; //表示小數點後的位數
}
return 0;
}
程式執行結果:
Zoot 1.2
Jimmy 35.4
AI 653.7
Stan 4358.2
請按任意鍵繼續. . .
控制輸出精度例子(設定scientific科學計數法,setprecision表示小數點後幾位)
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(void)
{
double values[] = { 1.23,35.36,653.7,4358.24 };
string names[] = { "Zoot","Jimmy","AI","Stan" };
cout << setiosflags(ios_base::scientific); //科學計數法
for (int i = 0; i < 4; i++) {
cout << setiosflags(ios_base::left)
<< setw(6)
<< names[i]
<<resetiosflags(ios_base::right)
<<setw(10)
<<setprecision(1)<<values[i]<<endl;
}
return 0;
}
Zoot 1.2e+00
Jimmy 3.5e+01
AI 6.5e+02
Stan 4.4e+03
請按任意鍵繼續. . .
向二進位制檔案輸出
二進位制檔案流
- 使用
ofstream
建構函式中的模式參量指定二進位制檔案輸出模式- 以通常方式構造一個流,然後使用
setmode
成員函式,在檔案開啟後改變模式- 通過二進位制檔案輸出流物件完成輸出
二進位制檔案輸出例子
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
using namespace std;
struct Date {
int mon, day, year;
};
int main(void)
{
Date dt = {6,10,92};
ofstream file("date.dat", ios_base::binary);
file.write(reinterpret_cast<char *>(&dt),sizeof(dt));
file.close();
return 0;
}
在工程目錄下可以檢視到這個二進位制檔案
向字串輸出檔案
典型應用:將資料輸出到字串可以將資料轉化為字串型別
字串輸出流
- 用於構造輸出流(
ostringstream
)- 功能
- 支援
ofstream
類的除open
、close
外的所有操作str
函式可以返回當前已構造的字串- 典型應用
- 將數值轉化為字串
將數值轉化為字串例子
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
template <class T>
inline string toString(const T &v) {
ostringstream os; //建立字串流
os << v; //將變數v寫入字串流
return os.str(); //返回輸出的流生成的字串
}
int main(void)
{
string s1 = toString(5);
cout << s1 << endl;
string s2 = toString(1.2);
cout << s2 << endl;
return 0;
}
程式碼執行效果:
5
1.2
請按任意鍵繼續. . .
輸入流類
重要的輸入流類
istream
類最適合用於順序文字模式輸入,cin是它的例項ifstream
類支援磁碟檔案輸入istringstream
構造輸入流物件
- 如果在建構函式中指定一個檔名,在構造該物件時該檔案自動開啟。
ifstream myFile("filename");
- 在呼叫預設建構函式之後用open函式開啟檔案。
ifstream myFile;
//建立一個檔案流物件
myFile.open("filename");
//開啟檔案“filename”- 開啟檔案模式可以指定
ifstream myFile("filename",ios_base::in|ios_base::binary);
使用提取運算子從文字檔案輸入
- 提取運算子
<<
對於所有標準C++
資料型別都是預先設計好的- 是從一個輸入流物件獲取位元組最容易的方法
ios
類中的很多操縱符都可以應用到輸入流。但是隻有少數幾個對輸入流物件具有實際影響,其中最重要的是進位制操縱符dec
、oct
和hex
輸入流相關函式
open
函式把該流與一個特定磁碟檔案相關聯get
函式的功能與提取運算子(>>
)很相像,主要的不同點是get
函式在讀入資料時包括空白字元。getline
的功能是從輸入流中讀取多個字元,並且允許指定輸入終止字元讀取完成後,從讀取的內容中刪除終止字元。read
成員函式從一個檔案讀位元組到一個指定的記憶體區域,由長度魯數確定要讀的位元組數。當遇到檔案結束或者在文字模式檔案中遇到檔案結東標記字元時結東束讀取seekg
函式用來設定檔案輸入流中讀取資料位置的指標tellg
函式返回當前檔案讀指標的位置close
函式關閉與一個檔案輸入流關聯的磁碟檔案
get函式應用舉例
#include <iostream>
using namespace std;
int main() {
char ch;
while ((ch = cin.get()) != EOF)
cout.put(ch);
return 0;
}
為輸入流指定一個終止字元
#include <iostream>
#include <string>
using namespace std;
int main() {
string line;
cout << "Type a line terminated by 't'" << endl;
getline(cin, line, 't');
cout << line << endl;
return 0;
}
程式碼執行結果:
Type a line terminated by 't'
qweteeeee
qwe
請按任意鍵繼續. . .
從檔案讀一個二進位制記錄到一個結構中
#include <fstream>
#include <cstring>
#include <iostream>
using namespace std;
struct SalaryInfo {
unsigned id;
double salary;
};
int main() {
SalaryInfo employee1 = {600001,8000};
ofstream os("payroll", ios_base::out | ios_base::binary);
os.write(reinterpret_cast<char *>(&employee1),sizeof(employee1));
os.close();
ifstream is("payroll", ios_base::out | ios_base::binary);
if (is) {
SalaryInfo employee2;
is.read(reinterpret_cast<char *>(&employee2), sizeof(employee2));
cout << employee2.id << employee2.salary << endl;
}
else {
cout << "ERROR:Can not open file" << endl;
}
is.close();
return 0;
}
程式運算結果:
6000018000
請按任意鍵繼續. . .
函式位置指標
#include <fstream>
#include <cstring>
#include <iostream>
using namespace std;
struct SalaryInfo {
unsigned id;
double salary;
};
int main() {
int values[] = {3,7,0,5,4};
ofstream os("payroll", ios_base::out | ios_base::binary);
os.write(reinterpret_cast<char *>(&values),sizeof(values));
os.close();
ifstream is("payroll", ios_base::out | ios_base::binary);
if (is) {
int v;
is.seekg(3 * sizeof(int));
is.read(reinterpret_cast<char *>(&v), sizeof(int));
cout << "the 4th is"<<v<< endl;
}
else {
cout << "ERROR:Can not open file" << endl;
}
is.close();
return 0;
}
程式碼執行結果:
the 4th is 5
請按任意鍵繼續. . .
字串輸入流
字串輸入流(
istringstream
)
- 用於從字串讀取資料
- 在建構函式中設定要讀取的字串
- 功能
- 支援
ifstream
類的除open
、close
外的所有操作- 典型應用
- 將字串轉化為數值
從字串輸入
#include <fstream>
#include <cstring>
#include <iostream>
#include <sstream>
using namespace std;
template <class T>
inline T fromString(const string& str) {
istringstream is(str); //建立字串輸入流
T v;
is >> v; //從字串輸入流中讀取變數v
return v; //返回變數v
}
int main(){
int v1 = fromString<int>("5");
cout << v1 << endl;
double v2 = fromString<double>("1.2");
cout << v2 << endl;
return 0;
}
5
1.2
請按任意鍵繼續. . .
輸入/輸出流
兩個重要的輸入輸出流
- 一個
iostream
物件可以是資料的源或目的- 兩個重要的
I/O
流類都是從iostream
派生的,他們是fstream
和stringstrea
m。這些類繼承了前面描述的istream
和ostream
類的功能
fstream
類
fstream
類支援磁碟檔案輸入或輸出- 如果需要在同一程式中從一個特定磁碟檔案讀並寫到該磁碟檔案,可以構造一個
fstream
物件- 一個
fstream
物件是有兩個邏輯子流的單個流,兩個子流一個用於輸入,另一個用於輸出
stringstream
類
stringstream
類支援面向字串的輸入輸出可以用與對同一個字串的內容交替讀寫,同樣是由兩個邏輯子流構成