【问题标题】:Using fstream::seekg under windows on a file created under Unix在 Unix 下创建的文件上在 windows 下使用 fstream::seekg
【发布时间】:2014-11-17 12:59:01
【问题描述】:

我有一个 C++ 跨平台程序(在 Linux 下用 g++ 编译,在 PC 下用 Visual Studio 编译)。该程序将行写入文本文件(使用<< 运算符和std::endl),但也可以从生成的文本文件中读回数据(使用std::getline)。

为了优化数据访问和节省内存,在读取数据文件时,我第一次读取它并将数据位置保存在我的程序中。当需要数据时,我稍后使用seekg 移动到特定位置并读取数据。

  • 在 PC 上创建和读取文件工作正常。
  • 在 Linux 上创建和读取文件工作正常。
  • 但在 Linux 上创建文件并在 PC 上读取失败。

在 PC 下, seekg 有时无法相应地移动光标。我可以在下面的示例中隔离问题。它读取文件一次,保存第二行位置和值,然后移回保存的位置并再次读取该行。

#include <fstream>
#include <iostream>
#include <string>
#include <assert.h>
int main()
{
    std::fstream file;
    file.open( "buglines.txt", std::ios_base::in );
    if ( file.is_open() )
    {
        std::streampos posLine2;
        std::string lineStr;
        std::string line2Str;
        int line = 1;
        while ( std::getline( file, lineStr ) )
        {
            if ( line == 1 )
                posLine2 = file.tellg(); // save line 2 position
            if ( line == 2 )
                line2Str = lineStr; // save line 2 content

            ++line;
            std::cout << lineStr <<std::endl;
        }
        std::cout << "Reached EOF, trying to read line 2 a second time" << std::endl;
        file.clear(); // clear EOF flag
        file.seekg(posLine2); // move to line 2
        std::getline( file, lineStr ); // read the line
        assert( lineStr == line2Str ); // compare

    }
    return 0;
}

我在 Windows 上运行它。

  • 如果 buglines.txt 是在 Windows 下创建的(十六进制编辑器将行分隔符显示为 2 个字符 0x0D 0x0A),它可以工作 (lineStr == line2Str)。
  • 如果buglines.txt 是在Linux 下创建的(十六进制编辑器将行分隔符显示为1 个字符0x0A),它不起作用(lineStr 是空字符串)。即使 getline 循环运行良好。

我知道两个系统对 EOL 的处理方式不同,但由于我只是使用 getline 函数进行阅读,我希望它能够巧妙地工作......我错过了什么吗?

【问题讨论】:

  • 你是否在使用 mingw 来制作 windows 二进制文件?
  • 不,Visual Studio 2010 SP1
  • 它也链接了哪个版本的 msvcrt?
  • msvcrt.dll: 7.0.7601.17744
  • 该版本可能存在错误,至少根据旧的mingw page,尝试与更新的东西链接,VS 2010 应该与 10.0.something 捆绑在一起。

标签: c++ linux windows fstream eol


【解决方案1】:

我无法轻松升级我的项目的运行时库,而且显然没有其他“解决方案”。

我尝试在文件打开时设置std::ios_base::binary 属性。它修复了报告的问题,但引入了一个新问题:使用getline 读取文件时,我们会得到额外的\r 字符。

因此,如果有人遇到同样的问题并需要修复,这里有一个解决方法:只需关闭文件,重新打开它,然后吃掉前 n 个字符,将读取指针移动到正确的位置:

#include <fstream>
#include <iostream>
#include <string>
#include <assert.h>

int main()
{
    std::fstream file;
    const std::string fileName = "buglines.txt";
    file.open( fileName.c_str(), std::ios_base::in );
    if ( file.is_open() )
    {
        std::streampos posLine2;
        std::string lineStr;
        std::string line2Str;
        int line = 1;
        while ( std::getline( file, lineStr ) )
        {
            if ( line == 1 )
                posLine2 = file.tellg(); // save line 2 position
            if ( line == 2 )
                line2Str = lineStr; // save line 2 content

            ++line;
            std::cout << lineStr << std::endl;
        }
        std::cout << "Reached EOF, trying to read line 2 a second time" << std::endl;
        //file.clear(); // clear EOF flag
        //file.seekg(posLine2); // move to line 2
        file.close();
        file.open( fileName.c_str(), std::ios_base::in );
        assert( file.is_open() );
        char* temp = new char[static_cast<int>(posLine2)+1];
        file.read( temp, static_cast<int>(posLine2)+1 ); // if posLine2 is too big, consider splitting with in a loop
        delete [] temp;
        assert( file.tellg() == posLine2 );

        std::getline( file, lineStr ); // read the line
        assert( lineStr == line2Str ); // compare
    }
    return 0;
}

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 2020-08-29
    • 2013-03-18
    • 1970-01-01
    • 2012-03-13
    • 2011-01-19
    • 2013-12-28
    相关资源
    最近更新 更多