很久之前,我和Swalky在写Huffman
Tree压缩的时候,遇到了一个问题:我们想在一个已经写入了一些内容的文件中部(或头部)写一些内容(用于修改文件的一些meta信息),结果发现总是
不行。如果用ofstream的默认构造函数,文件原有内容就不会保留下来,如果用了ios::app,无论怎么用seekp来定位,所写的内容都会跟在
文件原有内容的最后面。怎么办呢?
本着RTFM的心态,他去看C++ Primer,我则去看TCPL,以及网上的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. |
我们注意到一个重要的区别:app会在每次写操作之前都把写指针置于文件末尾,而ate模式则只在打开时才将写指针置于文件末尾。于是我们非常兴奋地将ofstream置于ios::ate,结果发现seekp仍然不能正常工作。
于是我把TCPL的《流》一章反复读了几遍,尤其很认真地看了流的缓冲区streambuf的实现,我突然意识到,如果不赋予流读文件的能力,没有读的缓冲区,流就无法seekp到文件的中部。
我试着改用这段代码来构造流:
fstream(filename, ios::in|ios::out|ios::ate)
程序的运行成功了!我很兴奋,因为当时是通过对流的实现的分析推断出这个结论的。
后来有一次有人在群上问C中如何这么做,我经过一番实验,发现只有以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+的意思是同时读写,而且该文件必须已经存在。用w+是错误的,因为它会把现存文件的所有内容清空。
最后附上当时的测试代码(用一个宏开关来分别测试C和C++):
#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;
}
分享到:
相关推荐
描述:C++ 使用流的方式写和读取磁盘上的文件,与 C 语言中的 fopen、fget、fput 等函数的功能类似。 标签:C++ ofstream ifstream 一、打开文件 在 C++ 中,fstream 类提供了成员函数 open() 用于打开文件。open...
- `ios::ate`:定位到文件末尾,通常与 `ios::app` 搭配使用。 - `ios::binary`:以二进制模式打开文件,默认为文本模式。 - `ios::in`:以输入模式打开文件。 - `ios::out`:以输出模式打开文件,默认模式。 - `ios...
* `ios::ate`:文件打开后定位到文件尾 * `ios::binary`:以二进制方式打开文件,缺省的方式是文本方式 * `ios::in`:文件以输入方式打开(文件数据输入到内存) * `ios::out`:文件以输出方式打开(内存数据输出到...
* ios::ate:文件打开后定位到文件尾,ios:app就包含有此属性 * ios::binary:以二进制方式打开文件,缺省的方式是文本方式 * ios::in:文件以输入方式打开(文件数据输入到内存) * ios::out:文件以输出方式打开...
- ios::ate:打开文件时,文件指针会移动到文件尾。 - ios::binary:以二进制方式打开文件,与文本方式相对。 - ios::in:文件以输入方式打开,用于读取数据。 - ios::out:文件以输出方式打开,用于写入数据。 - ...
与之相对应的是 `ifstream`,主要用于将磁盘上的文件内容读入内存。为了更好地理解 `ofstream` 的工作原理和使用方法,本文将详细介绍其基本概念、如何打开文件、读写操作以及一些高级用法。 #### 二、基本概念 在 ...
与ofstream类似,你首先要创建ifstream对象,然后打开文件: ```cpp ifstream inputFile("example.txt"); inputFile.open(); ``` 读取文件数据时,使用析取器(>>)操作符: ```cpp string line; if (inputFile >> ...
* ios::ate:文件打开后定位到文件尾 * ios::binary:以二进制方式打开文件 * ios::in:文件以输入方式打开 * ios::out:文件以输出方式打开 * ios::nocreate:不建立文件,所以文件不存在时打开失败 * ios::...
在C++中,文件操作是程序设计中一个重要的部分,涉及到数据的持久化存储与读取。根据给定文件的信息,我们将深入探讨C++中文件操作的基础知识、关键概念以及具体的代码实现细节。 ### 文件流类:ofstream和ifstream...
文件打开模式可以组合使用,如ios::in|ios::out表示追加模式,ios::app表示在文件末尾添加数据,ios::ate表示将文件指针初始设置在文件尾,ios::trunc表示如果文件存在则清空,ios::binary表示以二进制方式处理文件...
- **ios::ate**: 打开文件并定位到文件末尾。 - **ios::in**: 打开文件以供读取。 - **ios::out**: 打开文件以供写入。 - **ios::trunc**: 如果文件已存在,其内容会被截断。 - **示例**: ```cpp ofstream ...
* ios::ate:从文件尾开始 * ios::app:所有输出附加在文件末尾 * ios::trunc:如果文件已存在,则先删除该文件 * ios::binary:以二进制方式打开文件 这些模式可以被组合使用,中间以“|”符号间隔。 例如,要以...
这些类的对象需要首先与一个真正的文件关联,也就是说打开一个文件。要打开一个文件,我们可以使用成员函数 open(),其格式为: void open (const char * filename, openmode mode); 其中,filename 是要打开的...
`ios::ate`则初始位置在文件末尾,但后续写操作可能改变这一位置。 5. 文件操作实例: - 通过`ofstream`创建顺序文件,例如创建客户数据文件`Client.dat`,读取用户输入的数据并写入文件,直到遇到Ctrl+Z结束输入...
- `ios::ate`:初始位置设为文件尾。 - `ios::app`:所有输出追加到文件末尾。 - `ios::trunc`:如果文件已存在,先删除文件。 - `ios::binary`:以二进制模式打开文件。 例如,要以追加模式和二进制方式打开 ...
- `ios::ate`:初始位置设置在文件尾部。 - `ios::app`:所有的输出都被追加到文件末尾。 - `ios::trunc`:如果文件已经存在,则先删除该文件再打开。 - `ios::binary`:以二进制方式打开文件。 #### 三、默认打开...
* ios::ate:初始位置:文件尾 * ios::app:追加方式写文件 * ios::trunc:如果文件存在先删除,再创建 * ios::binary:二进制方式 注意:文件打开方式可以配合使用,利用|操作符。 读文件: 1. 包含头文件:#...
- `ios::ate`:初始位置:文件尾。 - `ios::app`:所有输出附加在文件末尾。 - `ios::trunc`:如果文件已存在则先删除该文件。 - `ios::binary`:二进制方式。 **示例**:假设我们需要以二进制方式打开名为`...
- **`ios::ate`**:文件打开后定位到文件末尾。 - **`ios::binary`**:以二进制模式打开文件。 - **`ios::in`**:以输入模式打开文件。 - **`ios::out`**:以输出模式打开文件。 - **`ios::nocreate`**:如果...