寫在前面的話:C++中對文件的操作跟C語言是有很大差別的,因此總結一下C++對文件的操作。
1、通常用法
在C++中隊文件的輸入輸出流和對內存的輸入輸出流以及對字符串的輸入輸出流接口是一致的,如果輸入流能產生字節,可以用一個提取操作符從這個流中獲取信息。這個提取符產生並格式化目的對象所期望的信息類型。雖然輸入流用起來很方便,但是也有一個問題,在使用格式化的輸入機制,尤其是標准輸入時,會遇到和C語言中scanf()中同樣的問題。如果輸入一個非期望值,進程則被偏離,而且它很難恢復。另外,格式化的輸入缺省以空格為分隔符。那么如下面的代碼:
#include <iostream> using namespace std; int main(void) { int i; cin >> i; float f; cin >> f; char c; cin >> c; char buf[100]; cin >> buf; cout << "i = " << i << endl; cout << "f = " << f << endl; cout << "c = " << c << endl; cout << "buf = " << buf << endl; cout << flush; cout << hex << "0x" << i << endl; return 0; }
給出以下輸入:
12 1.4 c this is a test
我們應該得到與輸入相同的輸出。
12
1.4
c
this is a test
但是實際輸出為:
12
1.4
c
this
注意到buf只得到第一個字,這個由於輸入機制是通過尋找空格來分隔輸入的,而空格在“this”的后面。另外如果連續的輸入串長於為buf分配的存儲空間,也會發生buf溢出現象。
2、面向行的輸入
要獲取一行輸入,有兩種選擇:成員函數get()、getline()。兩個函數都是有三個參數:指向存儲結果緩沖區的指針、緩沖區大小(不能超過其限度)和知道什么時候停止輸入的終止符。終止符有一個經常用到的缺省值‘\n’。兩個函數遇到輸入終止符時,都把零存儲在結果緩沖區里。
它們的區別如下:
1. get()遇到輸入流的分隔符就停止,而不從輸入流中提取分隔符。如果用相同的分隔符再調用一次get()函數,它會立即返回而不帶任何輸入。
2. getline()與其相反,它從輸入流中提取分隔符,但仍沒有把存儲在結果緩沖區里。
總之,當我們在處理文本文件時,無論什么時候需要讀出一行,都會想到getline()函數。
3、讀取原始字節
如果要讀取原始字節,即二進制代碼的話,可以使用read()函數,第一個參數指向內存目的地址的指針,第二個參數指明要讀取的字節數。
4、寫入原始字節
如果要寫入原始字節,使用write()函數。
遇到的問題:輸入流什么時候返回假值?
如下面的程序:
#include <iostream> #include <fstream> #include <assert.h> using namespace std; const int SZ = 100; int main() { char buf[SZ]; { ifstream in("strfile.cpp"); assert(in); ofstream out("strfile.out"); assert(out); int i = 1; while(in.get(buf, SZ)) { in.get(); // throw away next character cout << buf << endl; out << i++ << ": " << buf << endl; } } ifstream in("strfile.out"); assert(in); while(in.getline(buf, SZ)) { char *cp = buf; while(*cp != ':') { cp++; } cp += 2; cout << cp << endl; // must still add \n } }
其中的文件輸入流不是應該在文件結尾處才返回假值么?但是實際運行是,如果遇到空行程序就從while循環中跳出了,這個為什么呢?