ofstream与ate的故事
很久之前,我和Swalky在寫Huffman Tree壓縮的時候,遇到了一個問題:我們想在一個已經(jīng)寫入了一些內(nèi)容的文件中部(或頭部)寫一些內(nèi)容(用于修改文件的一些meta信息),結(jié)果發(fā)現(xiàn)總是 不行。如果用ofstream的默認構(gòu)造函數(shù),文件原有內(nèi)容就不會保留下來,如果用了ios::app,無論怎么用seekp來定位,所寫的內(nèi)容都會跟在 文件原有內(nèi)容的最后面。怎么辦呢?
本著RTFM的心態(tài),他去看C++ Primer,我則去看TCPL,以及網(wǎng)上的C++ Reference( http://www.cplusplus.com/reference/ ):
mode
Flags describing the requested i/o mode for the file. This is an object of type ios_base::openmode, which consists on a combination of one or more of the following flags defined as member constants:
flag value opening mode
| app | (app?end) Set the stream's position indicator to the end of the stream before each output operation. |
| ate | (at e?nd) Set the stream's position indicator to the end of the stream on opening. |
| binary | (binary?) Consider stream as binary rather than text. |
| in | (in?put) Allow input operations on the stream. |
| out | (out?put) Allow output operations on the stream. |
| trunc | (trunc?ate) Any current content is discarded, assuming a length of zero on opening. |
我們注意到一個重要的區(qū)別:app會在每次寫操作之前都把寫指針置于文件末尾,而ate模式則只在打開時才將寫指針置于文件末尾。于是我們非常興奮地將ofstream置于ios::ate,結(jié)果發(fā)現(xiàn)seekp仍然不能正常工作。
于是我把TCPL的《流》一章反復讀了幾遍,尤其很認真地看了流的緩沖區(qū)streambuf的實現(xiàn),我突然意識到,如果不賦予流讀文件的能力,沒有讀的緩沖區(qū),流就無法seekp到文件的中部。
我試著改用這段代碼來構(gòu)造流:
?
Cpp代碼?
?
?
?
程序的運行成功了!我很興奮,因為當時是通過對流的實現(xiàn)的分析推斷出這個結(jié)論的。
后來有一次有人在群上問C中如何這么做,我經(jīng)過一番實驗,發(fā)現(xiàn)只有以r+模式打開文件,fseek才起作用。這其實仍是基于同樣的原理。這里把C的fopen文檔貼出來:
mode
C string containing a file access modes. It can be:
| "r" | Open a file for reading. The file must exist. |
| "w" | Create an empty file for writing. If a file with the same name already exists its content is erased and the file is treated as a new empty file. |
| "a" | Append to a file. Writing operations append data at the end of the file. The file is created if it does not exist. |
| "r+" | Open a file for update both reading and writing. The file must exist. |
| "w+" | Create an empty file for both reading and writing. If a file with the same name already exists its content is erased and the file is treated as a new empty file. |
| "a+" | Open a file for reading and appending. All writing operations are performed at the end of the file, protecting the previous content to be overwritten. You can reposition (fseek?,?rewind?) the internal pointer to anywhere in the file for reading, but writing operations will move it back to the end of file. The file is created if it does not exist |
r+的意思是同時讀寫,而且該文件必須已經(jīng)存在。用w+是錯誤的,因為它會把現(xiàn)存文件的所有內(nèi)容清空。
最后附上當時的測試代碼(用一個宏開關(guān)來分別測試C和C++):
?
Cpp代碼?
?
#include <iostream> #include <fstream> #include <string> #include <cstdio> using namespace std; int main() { const char * original = "012345678901234567890123456789"; //30 chars const char * overwrite = "abcdeabcde"; const char * filename = "test.txt"; fstream fout; fout.open(filename, ios::out|ios::trunc); //destroy any current content fout << original; fout.close(); #define TESTING_CPP 1 #if TESTING_CPP fout.open(filename, ios::in|ios::out|ios::ate); fout.seekp(7); fout << overwrite; fout.close(); #else FILE * fout_c; if(fout_c = fopen(filename, "r+")) { fseek(fout_c, 7, SEEK_SET); fprintf(fout_c, overwrite); fclose(fout_c); } #endif //TESTING_CPP fout.open(filename, ios::in); while(!fout.eof()) { cout << static_cast<char>(fout.get()); } return 0; }?
總結(jié)
以上是生活随笔為你收集整理的ofstream与ate的故事的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql bit类型 使用select
- 下一篇: ofstream与ate的故事 经典!