在Windows下使用fstream :: seekg在Unix下创建的文件

时间:2014-11-17 12:59:02

标签: c++ linux windows fstream eol

我有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运行的。

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

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

1 个答案:

答案 0 :(得分:0)

我无法轻松升级项目的运行时库,因为显然没有其他解决方案&#34;。

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

因此,如果有人遇到同样的问题需要修复,这里有一个解决方法:只需关闭文件,重新打开它,然后吃前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;
}