У меня есть C ++ кроссплатформенная программа (скомпилированная с g ++ под Linux и с Visual Studio под ПК). Эта программа записывает строки в текстовый файл (используя <<
оператор и std::endl
), но также может считывать данные обратно из сгенерированного текстового файла (используя std::getline
).
Чтобы оптимизировать доступ к данным и сохранить память, при чтении файла данных я впервые читаю его и сохраняю положение данных в моей программе. Когда нужны данные, я позже использую 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
функция для чтения, я надеялся, что это будет работать умно … я что-то упустил?
Я не могу легко обновить библиотеку времени выполнения для своего проекта, и, как видно, другого «решения» нет.
Я пытался установить 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;
}