【问题标题】:reading windows file; _stat returns incorrect value读取windows文件; _stat 返回不正确的值
【发布时间】:2011-10-31 22:20:07
【问题描述】:

我的学校给了我一个小库来做一些项目。这个库是用 linux 编写的,所以我试图改变一些东西来使用我的 MinGW 编译器。一个特定的程序用于读取给定 URL 的文件。我不得不将 stat 更改为 _stat 以使其正常工作。打开文件工作正常,但 _stat 似乎返回不正确的值。我将在下面包含相关代码:

#ifdef WIN32
    #define stat _stat
#endif

    //return true if the number of chars read is the same as the file size
bool IsDone() const
{
    cout << "checking if numRead " << numRead << " is fileSize " << fileSize << endl;
    return (numRead == fileSize);
}

char Read()
{
    if (IsDone())
        throw IllegalStateException("stream is done");
    else
    {
        char c;
        file.get(c);
        cout << "reading: " << c << endl;
        if (file.fail())
            throw FileException(std::string("error reading from file ") + fileName);

        ++numRead;
        return c;
    }
}

void OpenFile(string fileName)
{
    struct stat buf;
    #ifdef WIN32
        if (_stat(fileName.c_str(), &buf) < 0){
            switch (errno){
                case ENOENT:
                  throw FileException(std::string("Could not find file ") + name);
                case EINVAL:
                    throw FileException(std::string("Invalid parameter to _stat.\n"));
                default:
                  /* Should never be reached. */
                    throw FileException(std::string("Unexpected error in _stat.\n"));
            }
        }
    #else
        if (stat(fileName.c_str(), &buf) < 0)
            throw FileException(std::string("could not determine size of file ") + fileName);
    #endif
        fileSize = buf.st_size;
        file.open(fileName.c_str());
}

如果您想查看整个库,可以从here 获取。我知道代码看起来很粗糙;我只是想拼凑一个工作的Windows版本。这东西在 Linux 上运行良好;问题是,当我在 Windows 上读取文件时,我在输入文件中使用的每个换行符的大小都是 1 短,所以如果我有一个看起来像这样的文件:

 text

它工作正常,但有:

text\r\n
 

它中断了,输出如下所示:

checking if numRead 0 is fileSize 6
checking if numRead 0 is fileSize 6
reading: t
checking if numRead 1 is fileSize 6
checking if numRead 1 is fileSize 6
reading: e
checking if numRead 2 is fileSize 6
checking if numRead 2 is fileSize 6
reading: x
checking if numRead 3 is fileSize 6
checking if numRead 3 is fileSize 6
reading: t
checking if numRead 4 is fileSize 6
checking if numRead 4 is fileSize 6
reading:

checking if numRead 5 is fileSize 6
checking if numRead 5 is fileSize 6
reading:
File Error: error reading from file H:/test/data/stuff.txt

它中断是因为 IsDone() 错误地返回 false(没有双关语),并且程序试图读取文件末尾。关于为什么 _stat 在有换行符时返回错误数字的任何建议?

【问题讨论】:

    标签: c++ windows file mingw newline


    【解决方案1】:

    _stat 返回的内容是完全正确的。 Windows 使用 "\r\n" 来表示行的结束,但是当您以文本模式打开文件时,在您读取流时它将被转换为单个换行符。

    如果您希望读取的流与外部长度匹配,请改为以二进制模式打开文件。

    如果您能原谅我这么说,一旦您完成了这些,我的建议是扔掉这段代码,并更改您的姓名,这样如果有人看到您的帖子,他们就不会因此而责备您。你这里有很多代码,至少在我看来,这些代码使一个简单的任务变得更加复杂和困难。

    【讨论】:

    • 文件大小和文件中数据的逻辑大小不必相同。在这种情况下,“test\ntest\n”与“test\r\ntest\r\n”具有相同的逻辑数据,但前者短了两个字节。一个简单地使用一个字节来编码一行的结尾,而后者使用两个字节来做到这一点。如果您关心这种差异,则需要以同样关心的方式读取文件。 (理想情况下,不是逐行。)
    • @Jerry Coffin:不介意你这么说。我将编辑这个问题,使其更加专注,并且没有一堆垃圾代码(这是其他人写的,我正忙于在 Windows 上工作)。
    【解决方案2】:

    在我看来,您应该以二进制模式打开文件。不知道为什么需要使用 stat 来读取文件,并且在 Windows 版本的代码中,您调用 _stat 然后再次调用 stat。

    在 Windows 中有几种方法可以做到这一点。我个人的偏好是使用类似的东西:

    char strBuffer[1024];
    
    FILE *fp = fopen (file,"rb");  // Binary read mode
    while (!feof (fp))
       fread (strBuffer,1,sizeof (strBuffer),fp);
    
    fclose (fp);
    

    【讨论】:

    • 哦,不。他的代码是一个非常长的、迂回的到达那里的方法,但至少看起来它可能是正确的。上面的循环很简单wrong
    • 这只是摘录,不是解决方案。我只是想给他指出一个不同的方向。显然,他需要做额外的检查,比如确保 fp 在 fopen 之后不为 NULL,然后他需要在每次迭代时获取 fread 读取的字节数并将 strBuffer 存储在某处,以便他拥有文件的全部内容。
    • 它可能是一个摘录,但不是来自实际工作的代码。阅读链接的咆哮。正如我在那里指出的那样,while (!feof(whatever)) 形式的循环本质上总是错误的。
    • 有趣的咆哮。我已经用这种方式很多次了,从来没有遇到过问题。也许我错过了它,但我没有看到任何解释为什么这不起作用或极端情况是什么。如果 feof 不起作用,那还有什么意义?
    • 甚至微软也有一个例子可以做到这一点。现在好吧,它是微软,但我不明白为什么这不起作用。 msdn.microsoft.com/en-us/library/xssktc6e%28v=VS.71%29.aspx
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-20
    相关资源
    最近更新 更多