【问题标题】:Why can't I read and append with std::fstream on Mac OS X?为什么我不能在 Mac OS X 上读取和附加 std::fstream?
【发布时间】:2010-02-21 09:43:36
【问题描述】:

考虑下面的 C++ 程序,它接受一个文件并打印每一行。这是一个更大程序的一部分,我稍后会根据我看到的内容将其附加到文件中。

#include <fstream>
using std::fstream;
#include <iostream>
#include <string>
using std::string;

int main()
{
 fstream file("file.txt", fstream::in | fstream::out | fstream::app);

 string line;
 while (std::getline(file, line))
  std::cerr << line << std::endl;

 return 0;
}

现在应用这个版本的file.txt(第一行一个单词,后跟一个换行符):

Rain

在我的机器 (Snow Leopard) 上,这不会打印任何内容。仔细检查,第一次调用 getline 失败。奇怪的是,如果我添加第二行,它也会失败:仍然没有打印任何内容!

谁能解开这个谜?

【问题讨论】:

  • 你的程序适合我,所以它可能是你环境中的一个错误。您是否尝试过以只读方式打开,即 fstream::in
  • 在这里也可以正常工作,按照 Earwicker 所说的做,并检查您的文件是否被实际打开。
  • 顺便说一句,您将文本发送到 std::cerr - std::cout 对于实际输出来说会更正常。 std::cerr 用于错误报告(如我的回答)。
  • @Charles,Manuel - 你真的尝试过吗?我刚刚在 Leopard 的 g++ 上构建了上面的确切源代码,并且仅在删除 ::app 标志时才有效。
  • 我在 Windows Vista + MSVC 2008 上试过

标签: c++ stl cross-platform fstream


【解决方案1】:

当你说:

fstream file("file.txt", fstream::in | fstream::out | fstream::app);

您以附加模式打开文件 - 即在最后。只需在阅读模式下打开它:

fstream file("file.txt", fstream::in );

或使用 ifstream:

ifstream file("file.txt" );

当然,正如 Earwicker 所建议的,您应该始终测试打开是否成功。

如果确定要以追加模式打开,可以显式移动读取指针:

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

int main() {
    fstream file( "afile.txt", ios::in | ios::out | ios::app );
    if ( ! file.is_open()  ) {
        cerr << "open failed" << endl;
        return 1;
    }
    else {
        file.seekg( 0, ios::beg );   // move read pointer
        string line;
        while( getline( file, line ) ) {
            cout << line << endl;
        }
    }
}

编辑: 似乎在打开文件时使用的标志组合会导致特定于实现的行为。以上代码适用于 Windows 上的 g++,但不适用于 Linux 上的 g++。

【讨论】:

  • 但是读位置不是独立于写位置的吗?
  • 显然不是——这是正确的答案。那些说他们在自己的系统上尝试过的人可能是在撒谎! :)
  • @Earwicker - 这是一个强烈的指控,可悲的是,对你来说这是一个完全没有根据的指控。并认为我赞成你的回答......
  • in | out | app 等同于 fopena+ 将读取位置定位在文件的开头,因此原始代码应该在符合要求的实现上工作。
  • @Earwicker:实际上,它的实现定义:7.19.3 说它的实现定义了文件是定位在附加模式下打开的文件的流的开头还是结尾,所以尼尔的建议明确seek 是唯一可移植的答案(假设需要附加模式)。
【解决方案2】:

你应该检查文件是否真的被打开了:

if (!file)
    std::cerr << "Oh dear" << std::endl;

更新:事实上该文件可能已被打开,但处于附加模式 - 请参阅 Neii 的回答。

更新 2: 好的,又错了。至少在 Leopard 的 g++ 中,不会打开文件,因为 app 标志与 in 标志不兼容。所以上面的检查会打印Oh dear

在 MSVC++ 中,它继续打开文件,显然读取位置在开头,这解释了为什么其他人看到它有效,我为怀疑他们的真实性道歉!

【讨论】:

    猜你喜欢
    • 2016-08-14
    • 2015-03-07
    • 1970-01-01
    • 2020-02-28
    • 1970-01-01
    • 2017-12-28
    • 1970-01-01
    • 2023-04-04
    相关资源
    最近更新 更多