?C++中的文件輸入/輸出(6):一些有用的函數

原作:Ilia Yordanov,? loobian@cpp-home.com


????
??? tellg() ——
返回一個 int 型數值,它表示“內置指針”的當前位置。此函數僅當你在讀取一個文件時有效。例如:
???
#include <fstream.h>
??? ?
??? void main()
??? {
??? ???
// 假如我們已經在 test_file.txt 中存有了“ Hello ”的內容
???
??? ifstream File("test_file.txt");
??? ?
??? ??? char arr[10];
??? ?
??? ??? File.read(arr,10);
??? ???
??? ???
// 由于 Hello 5 個字符,因此這里將返回 5
???
??? cout << File.tellg() << endl;
??? ?
??? ??? File.close();
??? }
???
???
tellp() —— tellg() 有同樣的功能,但它用于寫文件時。總而言之:當我們讀取一個文件,并要知道內置指針的當前位置時,應該使用 tellg() ;當我們寫入一個文件,并要知道內置指針的當前位置時,應該使用 tellp() . 由于此函數的用法與 tellg() 完全一樣,我就不給出示例代碼了。
???
??? seekp() ——
還記得 seekg() 么?當我在讀取一個文件,并想到達文件中某個特定位置時,就曾使用過它。 seekp() 亦如此,只不過它用于寫入一個文件的時候。例如,假如我在進行文件讀寫,而要定位到當前位置的三個字符之前,則需調用 FileHandle.seekg(-3) . 但如果我是在寫入一個文件,并且比如我要重寫后 5 個字符的內容,我就必須往回跳轉 5 個字符,因而,我應該使用 FileHandle.seekp(-5) .
???
??? ignore() ——
使用于讀取文件之時。如果你想略過一定數量的字符,只需使用此函數。實際上,你也可以使用 seekg() 來代替,然而使用 ignore() 有一個優點 —— 你可以指定一個特定“界限規則( delimiter rule )”,同樣使得 ignore() 在指定的位置停下。函數原型如下:
???
???
istream& ignore( int nCount, delimiter );
???
???
nCount 表示要略過的字符數量,而 delimiter —— 與它的名稱有著同樣的含義:假如你想在文件末尾停下,則可使用 EOF 值傳入,這樣一來此函數就等同于 seekg() ;但該參數還可以使用其他值,例如 ‘\n’ 這樣可以在換行的同時定位在新行處。下面是示例:
???
#include <fstream.h>
??? ?
??? void main()
??? {
??? ???
// 假設 test_file.txt 中已經存有 "Hello World" 這一內容
???
??? ifstream File("test_file.txt");
??? ?
??? ??? static char arr[10];
??? ?
??? ???
// 假如一直沒有遇到字符 "l" ,則向前定位直到跳過 6 個字符
???
??? // 而如果期間遇到 "l" ,則停止向前,定位在該處
???
??? File.ignore(6,'l');
??? ?
??? ??? File.read(arr,10);
??? ?
??? ??? cout << arr << endl;
// 它將顯示 "lo World!"
??? ?
???
??? File.close();
??? ?
??? }
???

??? getline() ——
雖然前面的章節中我曾提到過這個函數,但還有一些內容我們未曾涉及:此函數不但可用于逐行讀取,而且它還可以設為遇到某個特定字符后停止讀取。下面給出傳遞這一參數的方法:
???
???
getline(array,array_size,delim);
???
???
以下為示例代碼:
???
???
#include <fstream.h>
??? ?
??? void main()
??? {
??? ???
// 假設 test_file.txt 中已經存有 "Hello World" 這一內容
???
??? ifstream File("test_file.txt");
??? ?
??? ??? static char arr[10];
??? ?
??? ???
/* 讀取,直到滿足下面的條件之一:
??? 1
)已經讀取 10 個字符
??? 2
)遇到字母 "o"
??? 3
)出現新一行
???
??? */
??? ??? File.getline(arr,10,'o');
??? ?
??? ??? cout << arr << endl;
// 將顯示 "Hell"
???
??? File.close();
??? }
???

??? peek() ——
此函數將返回輸入流文件的下一個字符,但它不移動內置指針。我想你該記得,像 get() 這樣的函數也返回輸入流文件的下一個字符,而與此同時它將移動內置指針。所以當你再次調用 get() 函數的時候,它會返回再下一個字符,而非前面那個。哦,使用 peek() 也會返回字符,但它不會移動“光標”。所以,假如你連續兩次調用 peek() 函數,它會返回同一個字符。考慮以下代碼:
???
???
#include <fstream.h>
??? ?
??? void main()
??? {
??? ???
// 假設 test_file.txt 中已經存有 "Hello World" 這一內容
???
??? ifstream File("test_file.txt");
??? ?
??? ??? char ch;
??? ?
??? ??? File.get(ch);
??? ??? cout << ch << endl;
// 將顯示 "H"
??? ?
??? ??? cout <<??? char(File.peek()) << endl;
// 將顯示 "e"
??? ??? cout <<??? char(File.peek()) << endl;
// 將再次顯示 "e"
??? ?
??? ??? File.get(ch);
??? ??? cout << ch << endl;
// 還是顯示 "e"
???

??? File.close();
??? ???
??? }
???

???
順便說一下,我忘了講 ——peek() 函數實質上返回的是字符的 ASCII 碼,而非字符本身。因此,假如你想看到字符本身,你得像我在示例中做的那樣進行調用(譯注:即要轉為 char 類型)
???
??? _unlink() ——
刪除一個文件。假如你要使用此函數,需要在你的程序中包含 io.h 頭文件。下面是示例代碼:
???
???
#include <fstream.h>
??? #include <io.h>
??? ?
??? void main()
??? {
??? ??? ofstream File;
??? ?
??? ??? File.open("delete_test.txt");
// 創建一個文件
???
??? File.close();
??? ?
??? ??? _unlink("delete_test.txt");
// 刪除這個文件
???
?
??? ???
// 試圖打開此文件,但假如它已不存在
???
??? // 函數將返回一個 ios::failbit 錯誤值
???
??? File.open("delete_test.txt",ios::nocreate);
??? ?
??? ???
// 驗證它是否返回該值
???
??? if(File.rdstate() == ios::failbit)
??? ??? ??? cout << "Error...!\n";
// 耶,成功了
???
???
File.close();
??? ?
??? }
???

??? putback() ——
此函數將返回最后一個所讀取字符,同時將內置指針移動 -1 個字符。換言之,如果你使用 get() 來讀取一個字符后再使用 putback() ,它將為你返回同一個字符,然而同時會將內置指針移動 -1 個字符,所以你再次使用 get() 時,它還是會為你返回同樣的字符。下面是示例代碼:
???
???
#include <fstream.h>
??? ?
??? void main()
??? {
??? ???
// test_file.txt 應包含內容 "Hello World"
???
??? ifstream File("test_file.txt");
??? ???
??? ??? char ch;
??? ?
??? ??? File.get(ch);
??? ?
??? ??? cout << ch << endl;
// 將顯示 "H"
??? ?
??? ??? File.putback(ch);
??? ??? cout << ch << endl;
// 仍將顯示 "H"
??? ???
??? ??? File.get(ch);
??? ??? cout << ch << endl;
// 再一次顯示 "H"
??? ?
??? ??? File.close();
??? }
???
???
flush() —— 在處理輸出流文件的時候,你所存入的數據實際上并非立刻寫入文件,而是先放入一個緩沖區中,直到該緩沖區放滿數據之后,這些數據才被存入真正的文件中(在你的磁盤上)。旋即緩沖區會被清空,再重新進行下一輪寫入。
???
但假如你想在緩沖區寫滿之前就將其中的數據寫入磁盤,則使用 flush() 函數。只須像這樣進行調用: FileHandle.flush() ,這樣緩沖區內的數據將會寫入實際的物理文件,而后緩沖區被清空。
???
再補充一點(高階的)內容: flush() 函數會調用與相應流緩沖( streambuf )相聯系的 sync() 函數(出自 MSDN )。