如何在C++中使用`fstream`同时读写文件?

10

我有以下代码

#include<iostream>
#include<fstream>
#include<string>

using namespace std;

int main(void) {
    fstream ofile;
    ofile.open("test.txt", ios::in | ios::out | ios::app);
    for(string line; getline(ofile, line) ; ) {
        cout << line << endl;
    }
    ofile << "stackexchnange" << endl;
    ofile.close();
    return 0;
}

test.txt 包含内容

hello world!
stackoverflow

上面的代码输出

hello world!
stackoverflow

运行代码后,stackexchange 没有被追加到 test.txt 的末尾。如何在读取文件后进行写入?


9
我认为在向文件写入内容之前,你需要使用 ofile.clear(); 清除流的状态,因为一旦退出循环,流就会被设置为 badbit 或其他状态,这时你需要在继续执行任何操作之前调用 clear() 方法进行清除。这只是我的猜测,我并不确定。 - Nawaz
2
为什么你不检查I/O?如果你在执行ofile << "stackexchange" << endl;之后测试流状态,你会发现它失败了,告诉你出了问题。如果你在写入任何内容之前也测试状态,你会发现流状态在尝试写入之前就已经不好了。 - Jonathan Wakely
@JonathanWakely:不错的链接,尽管在固定示例中向std::cerr写入是多余的(坚持使用异常或return 1!),而且还缺少一个终止分号... - Lightness Races in Orbit
@LightnessRacesinOrbit,已经修复了缺失的分号,谢谢。我没有费心去修复冗余。我同意它可以做得更好,但我宁愿让人们检查并抱怨两次,也不要完全不检查 :) - Jonathan Wakely
2个回答

16
Nawaz的评论是正确的。您的读取循环会迭代直到 fstream::operator bool(来自ofile)返回false。因此,在循环之后,failbit或badbit必须已设置。当循环尝试进行最后一次读取但只剩下EOF时,将设置failbit。这完全没问题,但在再次使用流之前必须重置错误状态标志。
// ...
ofile.clear();
ofile << "stackexchnange" << endl;

6

fstream有两个位置:输入和输出。在您的情况下,当您打开文件时,它们都被设置为文件的开头。

因此,您有四种方法:

tellp // returns the output position indicator 
seekp // sets the output position indicator 
tellg // returns the input position indicator
seekg // sets the input position indicator 

在您的情况下,您可以使用以下行将输出位置设置到文件末尾。
ofile.seekp(0, std::ios_base::end);

我错过了ios :: app标志。我的错。@Nawaz的评论给出了正确的答案:在读取整个文件后需要调用

ofile.clear(); //cleanup error and eof flags

但是它应该在文件的开头写入。我尝试过,甚至没有写入到文件中。 - sonus21
但是他们使用ios::app模式打开了流。那么为什么在没有明确执行此操作的情况下进行写入时,输出位置不会自动定位到末尾呢? - eerorika
另外,为什么输出位置在开头不会导致文件开头被覆盖? - eerorika
我错过了 ios::app 标志。我的错。 @Nawaz 的评论给出了正确的答案:在读完整个文件后,需要调用 ofile.clear(); 清除错误和 eof 标志。 - Alexander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接