ofstream与ate的故事
很久之前,我和Swalky在寫Huffman Tree壓縮的時(shí)候,遇到了一個(gè)問題:我們想在一個(gè)已經(jīng)寫入了一些內(nèi)容的文件中部(或頭部)寫一些內(nèi)容(用于修改文件的一些meta信息),結(jié)果發(fā)現(xiàn)總是 不行。如果用ofstream的默認(rèn)構(gòu)造函數(shù),文件原有內(nèi)容就不會(huì)保留下來,如果用了ios::app,無論怎么用seekp來定位,所寫的內(nèi)容都會(huì)跟在 文件原有內(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. |
我們注意到一個(gè)重要的區(qū)別:app會(huì)在每次寫操作之前都把寫指針置于文件末尾,而ate模式則只在打開時(shí)才將寫指針置于文件末尾。于是我們非常興奮地將ofstream置于ios::ate,結(jié)果發(fā)現(xiàn)seekp仍然不能正常工作。
于是我把TCPL的《流》一章反復(fù)讀了幾遍,尤其很認(rèn)真地看了流的緩沖區(qū)streambuf的實(shí)現(xiàn),我突然意識(shí)到,如果不賦予流讀文件的能力,沒有讀的緩沖區(qū),流就無法seekp到文件的中部。
我試著改用這段代碼來構(gòu)造流:
?
Cpp代碼?
?
?
?
程序的運(yùn)行成功了!我很興奮,因?yàn)楫?dāng)時(shí)是通過對(duì)流的實(shí)現(xiàn)的分析推斷出這個(gè)結(jié)論的。
后來有一次有人在群上問C中如何這么做,我經(jīng)過一番實(shí)驗(yàn),發(fā)現(xiàn)只有以r+模式打開文件,fseek才起作用。這其實(shí)仍是基于同樣的原理。這里把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+的意思是同時(shí)讀寫,而且該文件必須已經(jīng)存在。用w+是錯(cuò)誤的,因?yàn)樗鼤?huì)把現(xiàn)存文件的所有內(nèi)容清空。
最后附上當(dāng)時(shí)的測(cè)試代碼(用一個(gè)宏開關(guān)來分別測(cè)試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的故事的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql bit类型 使用select
- 下一篇: ofstream与ate的故事 经典!