【问题标题】:Why does my program produce different results on Windows and Linux, about file reading with ifstream?为什么我的程序在 Windows 和 Linux 上产生不同的结果,关于使用 ifstream 读取文件?
【发布时间】:2012-03-22 07:05:51
【问题描述】:

我有一个如下所示的程序。对于它,我有几个问题:

1)。 为什么它在不同平台上会产生不同的结果?我稍后会粘贴屏幕截图。

2)。 我正在使用 fail() 方法来检查“file.read()”是否失败。这是正确的吗?我使用 fail() 方法是因为 this web page 是这样说的:

如果设置了failbit 或badbit,则该函数返回true。如果在输入操作期间发生除了到达文件结尾之外的错误,则至少设置这些标志中的一个。

但后来我读到了这个关于 istream::read() here 的页面。它说 eofbit 和 failbit 将始终同时设置.. 这是否意味着正常的 EOF 情况也会导致 fail() 返回 true?这似乎与“除了到达文件结束之外”发生冲突..

谁能帮我澄清我应该如何使用这些方法?我应该改用 bad() 吗?

我的程序

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

#ifdef WIN32
char * path="C:\\Workspace\\test_file.txt";
#else
char * path="/home/robin/Desktop/temp/test_file.txt";
#endif

int main(int argc, char * argv[])
{
    ifstream file;

    file.open(path);
    if (file.fail())
    {
        cout << "File open failed!" << endl;
        return -1;  // If the file open fails, quit!
    }

    // Calculate the total length of the file so I can allocate a buffer
    file.seekg(0, std::ios::end);
    size_t fileLen = file.tellg();
    cout << "File length: " << fileLen << endl;
    file.seekg(0, std::ios::beg);

    // Now allocate the buffer
    char * fileBuf = new (std::nothrow) char[fileLen+1];
    if (NULL == fileBuf)
        return -1;
    ::memset((void *)fileBuf, 0, fileLen+1);    // Zero the buffer

    // Read the file into the buffer
    file.read(fileBuf, fileLen);
    cout << "eof: " << file.eof() << endl
         << "fail: " << file.fail() << endl
         << "bad: " << file.bad() << endl;
    if (file.fail())
    {
        cout << "File read failed!" << endl;
        delete [] fileBuf;
        return -1;
    }

    // Close the file
    file.close();

    // Release the buffer
    delete [] fileBuf;

    return 0;
}

test_file.txt 内容(用“vim -b”显示。这是一个非常简单的文件):

Windows 上的结果(Visual Studio 2008 SP1):

Linux 上的结果(gcc 4.1.2):

【问题讨论】:

  • cplusplus.com 不是一个好的参考。它充满了不好的例子(比如测试不应该的流fail()成员)和事实错误。我推荐en.cppreference.com
  • 尝试以二进制模式打开文件。

标签: c++ ifstream


【解决方案1】:

这是否意味着正常的 EOF 情况也会导致 fail() 返回 true?这似乎与“除了到达文件结束之外”发生冲突。

我建议使用没有错误的参考。

http://en.cppreference.com/w/cpp/io/basic_ios/fail 说:

如果关联流发生错误,则返回 true。具体来说,如果在rdstate() 中设置了badbitfailbit,则返回true

C++ 标准说:

返回: true 如果在 rdstate() 中设置了 failbit 或 badbit

没有“除了文件结尾”的东西。尝试读取文件末尾的操作也会导致设置failbiteofbit 仅用于将特定的失败原因与其他原因区分开来(这并不像人们一开始想象的那么有用)。


我正在使用fail() 方法来检查“file.read()”是否失败。这是正确的吗?

您应该简单地转换为bool 进行测试。

if(file) { // file is not in an error state

它是!fail()的同义词,但它更有用,因为您可以使用它直接测试读取操作的结果而无需额外的括号(!(stream &gt;&gt; x).fail() 之类的东西会很尴尬):

if(file.read(fileBuf, fileLen)) { // read succeeded

您会注意到对流的所有读取操作都会返回流本身,这就是您可以这样做的原因。


为什么在不同的平台上会产生不同的结果?

您在 Windows 和 Linux 之间看到的差异是因为文件以文本模式打开:换行符将由实现静默转换。这意味着组合 "\r\n"(在 Windows 中用于换行符)将在 Windows 中转换为单个 '\n' 字符,使文件只有 8 个字符。请注意 vim 如何在第一行末尾显示 ^M:这就是 '\r' 部分。在 Linux 中,换行符只是 '\n'

如果你想保持原样,你应该以二进制模式打开文件:

file.open(path, std::ios_base::in | std::ios_base::binary);

【讨论】:

  • +1 for “我建议使用没有错误的参考。”
  • FTR,虽然我发现 cppreference.com 总体上比 cplusplus.com 好,但我并不是说它完全没有错误。主要区别在于,作为 wiki,我们实际上可以修复其中的错误。而最终的参考就是标准。
  • 关于!fail() 的使用和到bool 的转换,真正的区别在于将流本身用作布尔值是惯用的。这是读者希望看到的,如果你做其他事情,读者会问为什么。 (从技术上讲,没有到bool 的转换。有到指针类型的转换,以及operator! 的重载,它们一起允许流像bool 一样使用。)跨度>
  • @JamesKanze 真的。我要补充一点,在 C++11 中转换已更改为显式转换为 bool
  • @R.MartinhoFernandes:感谢您的详细解释!没错,我应该尝试以二进制模式打开文件!现在我这样做成功了。 BTW:也感谢您对 cppreference 的推荐!
【解决方案2】:

我猜,不同执行的问题在于 DOS(Window) 与 UNIX 文本文件约定。

在 DOS 中,一行以&lt;CR&gt;&lt;LF&gt; 结尾,这将作为'\n' 一起读/写。因此,在 Windows 中,您的文件位于末尾,但在 UNIX 中则不是,因为还剩一个字符。

【讨论】:

  • 这真的更像是一个评论
  • @sehe:不,这就是答案。问题在于将end of line序列转换为单个字符。
  • @LokiAstari 这是一个很好的提示,但我怀疑 OP 没有意识到 EOL 的差异。真正的问题表面上是“我应该如何以独立于平台的方式处理这个问题”?
  • @sehe 好吧,OP 提出了两个明确的问题,你再补充一个。也许您的问题更有趣,但这不是OP的问题。
  • “谁能帮我澄清一下我应该如何使用这些方法?我应该使用 bad() 代替吗?”
猜你喜欢
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-05
  • 1970-01-01
  • 2014-05-27
相关资源
最近更新 更多