Использование fstream :: seekg под windows для файла, созданного под Unix

У меня есть C ++ кроссплатформенная программа (скомпилированная с g ++ под Linux и с Visual Studio под ПК). Эта программа записывает строки в текстовый файл (используя << оператор и std::endl), но также может считывать данные обратно из сгенерированного текстового файла (используя std::getline).

Чтобы оптимизировать доступ к данным и сохранить память, при чтении файла данных я впервые читаю его и сохраняю положение данных в моей программе. Когда нужны данные, я позже использую seekg перейти к определенной позиции и прочитать данные.

  • Создание и чтение файла на ПК работает нормально.
  • Создание и чтение файла в Linux работает нормально.
  • Но создание файла в Linux и чтение на ПК не удается.

Под ПК поиск иногда не может соответственно переместить курсор. Я мог бы выделить проблему в примере ниже. Он читает файл один раз, сохраняет вторую позицию строки и значение, затем возвращается в сохраненную позицию и снова читает строку.

#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 функция для чтения, я надеялся, что это будет работать умно … я что-то упустил?

2

Решение

Я не могу легко обновить библиотеку времени выполнения для своего проекта, и, как видно, другого «решения» нет.

Я пытался установить 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;
}
0

Другие решения


По вопросам рекламы [email protected]