我有C ++一个跨平台程序(在Linux下使用g ++编译,在PC下使用Visual Studio编译)。此程序将行写入文本文件(使用<<
运算符和std::endl
),但也可以从生成的文本文件中读取数据(使用std::getline
)。
为了优化数据访问和节省内存,在读取数据文件时,我第一次读取它并在程序中保存数据位置。当需要数据时,我稍后使用seekg
移动到特定位置并读取数据。
在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
(十六进制编辑器将行分隔符显示为2个字符0x0D 0x0A
),则它可以正常工作(lineStr == line2Str
)。buglines.txt
(十六进制编辑器将行分隔符显示为1个字符0x0A
),则它不起作用(lineStr为空字符串)。即使getline循环工作得很好。我知道这两个系统与EOL的处理方式不同,但由于我只是使用getline
函数进行阅读,我希望它能够巧妙地工作......我错过了什么?
答案 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;
}