简体   繁体   English

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

[英]Using fstream::seekg under windows on a file created under Unix

I have C++ a cross-platform program (compiled with g++ under Linux and with Visual Studio under PC). 我有一个C ++跨平台程序(在Linux下与g ++以及在PC下与Visual Studio一起编译)。 This program writes lines to a text file (using << operator and std::endl ) but can also read data back from the generated text file (using std::getline ). 该程序将行写入文本文件(使用<<操作符和std::endl ),但也可以从生成的文本文件读回数据(使用std::getline )。

To optimize data access and save memory, when reading the data file, I read it a first time and save data position in my program. 为了优化数据访问并节省内存,在读取数据文件时,我会第一次读取它并将数据位置保存在程序中。 When data is needed, I later use seekg to move to a specific position and read the data. 当需要数据时,稍后我会使用seekg移动到特定位置并读取数据。

  • Creating and reading the file on PC works fine. 在PC上创建和读取文件可以正常工作。
  • Creating and reading the file on Linux works fine. 在Linux上创建和读取文件可以正常工作。
  • But creating the file on Linux and reading on PC fails. 但是在Linux上创建文件并在PC上读取失败。

Under PC, seekg sometime fails to move the cursor accordingly. 在PC下,seekg有时无法相应地移动光标。 I could isolate the problem in the example below. 我可以在下面的示例中隔离问题。 It reads the file once, saves second lineposition and value, then moves back to the saved position and reads the line again. 它读取一次文件,保存第二个行的位置和值,然后移回保存的位置并再次读取该行。

#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;
}

I'm running this from Windows. 我正在Windows上运行它。

  • If buglines.txt was created under Windows (hexadecimal editor shows line separators as 2 characters 0x0D 0x0A ), it works ( lineStr == line2Str ). 如果buglines.txt是在Windows下创建的(十六进制编辑器将行分隔符显示为2个字符0x0D 0x0A ),则它将起作用( lineStr == line2Str )。
  • If buglines.txt was created under Linux (hexadecimal editor shows line separators as 1 character 0x0A ), it does not works (lineStr is empty string). 如果buglines.txt是在Linux下创建的(十六进制编辑器将行分隔符显示为1个字符0x0A ),则它将不起作用(lineStr为空字符串)。 Even if the getline loop worked perfectly. 即使getline循环运行完美。

I know both system deals differently with EOL, but as I'm just using getline function for reading, I was hoping that it would smartly work...am I missing something? 我知道两个系统对EOL的处理方式都不同,但是由于我仅使用getline函数进行读取,因此我希望它可以正常运行...我是否缺少某些内容?

I can't easily upgrade the runtime library for my project and as, apparently, there is no other "solution". 我无法轻松地为我的项目升级运行时库,并且显然没有其他“解决方案”。

I tried to set std::ios_base::binary attribute upon file open. 我试图在打开文件时设置std::ios_base::binary属性。 It fixes the reported problem but introduces a new one: We get extra \\r chacters when reading the file with getline . 它解决了所报告的问题,但引入了一个新问题:使用getline读取文件时,我们会得到额外的\\r字符。

So if anyone has the same problem and needs a fix, here is a workaround: simply close the file, re-open it, and then eat the first n characters to move the read pointer to the good location: 因此,如果有人遇到相同的问题并需要修复,请采用以下解决方法:只需关闭文件,重新打开文件,然后吃掉前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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM