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

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

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

  • 在PC上创build和读取文件工作正常。
  • 在Linux上创build和读取文件工作正常。
  • 但是在Linux上创build文件并在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下创build的(hex编辑器将行分隔符显示为2个字符0x0D 0x0A ),它可以工作( lineStr == line2Str )。
  • 如果buglines.txt是在Linux下创build的(hex编辑器将行分隔符显示为1个字符0x0A ),它不起作用(lineStr是空string)。 即使getline循环完美工作。

我知道这两个系统交易与EOL不同,但由于我只是使用getline函数来阅读,所以我希望它能够巧妙地工作…我错过了什么?

Solutions Collecting From Web of "在Unix下创build的文件的Windows下使用fstream :: seekg"

我不能轻易升级我的项目的运行时库,显然,没有其他“解决方案”。

我试图在打开文件时设置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; }