Страницы

Поиск по вопросам

Показаны сообщения с ярлыком fstream. Показать все сообщения
Показаны сообщения с ярлыком fstream. Показать все сообщения

понедельник, 24 февраля 2020 г.

С++. Дважды прочитать файл. Библиотека fstream

#cpp #файлы #fstream


Доброго времени суток.

Возник такой вопрос. Как в библиотеке fstream дважды прочитать файл без его закрытия?

Нашел функции rewind() и fseek(file,0L,SEEK_SET), но они отказываются работать, если
открывать файл не функцией fopen из библиотеки stdio.h

Есть ли альтернатива для библиотеки fstream?
    


Ответы

Ответ 1



Посмотрите на seekg(). И, если нарвались на конец файла или иные неприятности - не забывайте сбросить состояние ошибки с помощью clear().

воскресенье, 16 февраля 2020 г.

С++. Дважды прочитать файл. Библиотека fstream

#cpp #файлы #fstream


Доброго времени суток.

Возник такой вопрос. Как в библиотеке fstream дважды прочитать файл без его закрытия?

Нашел функции rewind() и fseek(file,0L,SEEK_SET), но они отказываются работать, если
открывать файл не функцией fopen из библиотеки stdio.h

Есть ли альтернатива для библиотеки fstream?
    


Ответы

Ответ 1



Посмотрите на seekg(). И, если нарвались на конец файла или иные неприятности - не забывайте сбросить состояние ошибки с помощью clear().

среда, 10 июля 2019 г.

Парсинг бинарного файла

Необходимо распарсить файл. Формат данных более-менее приемлимый: экспорт заявок, размер файлов 1-25 мб, в каждой строке до символа ':' тэг, после него данные, строки кончаются 0x0D 0x0A, заявки отделены 0x0C).
Читал бы построчно, но проблема в символах 0x00, которых понатыкано очень много и в разных местах и последовательностях (да и 0x0A 0x0D местами 10-20 подряд).
Поэтому файл пробую читать как бинарный, для проверки пишу содержимое в другой файл.
Под debug нет проблем, в конце чтения выставляются EOF и FAIL, в конце записи почему-то BAD
Под release данные пишутся, но в конце записи все флаги не выставлены, в конце файла многочисленные символы 0x00 (для Unicode при сколько-нибудь крупном файле, странно - для мелочи в 1-100 строк такое не происходит) или вообще мусор в разнобой (для multibyte).
В чём может быть проблема? Тестировал на исходном файле с экспортом заявок и на файле-тестовике, генерируемом PrepareForTestBinary. Пробовал включить исключения для потоков, но ничего интереснее ios_base::failbit set ; iostream:1 не выдаёт.
У меня MS VS2010
Командная строка компилятора под Release
/Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Release\binread.pch" /Fa"Release\" /Fo"Release\" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:queue
Командная строка компилятора под Debug
/ZI /nologo /W3 /WX- /Od /Oy- /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\binread.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd /analyze- /errorReport:queue
Игры с опциями ничего не дали.
Вот код:
#ifndef _UNICODE #define TCOUT std::cout #else #define TCOUT std::wcout
typedef std::basic_ios tios; typedef std::basic_ifstream tifstream; typedef std::basic_ofstream tofstream; typedef std::basic_string tstring;
//проверка флагов для потоков void fState(tios &fs) { TCOUT << _T("fail bad eof good
"); TCOUT << (fs.rdstate()&fs.failbit) << _T(" ; ") << (fs.rdstate()&fs.badbit) << _T(" ; ") << (fs.rdstate()&fs.eofbit) << _T(" ; ") << (fs.rdstate()&fs.goodbit) << endl; }
//Для тестирования генерируем исходный файл void PrepareForTestBinary(tstring PATH) { tofstream os; os.open (PATH, ios_base::binary ||ios_base::out); for (int i = 0; i<200000;i++) os << _T("0123456789") << '\0' << _T("ABCDEFGHIJ") << std::endl; os.close(); } // Читаем и пишем void TestBinary(tstring inPATH,tstring outPATH) { LONGLONG len; TCHAR * buffer; tifstream is; fState(is); is.open (inPATH, ios_base::binary ||ios_base::in ); fState(is); is.seekg (0, ios::end); len = is.tellg(); is.seekg (0, ios::beg); buffer = new TCHAR [len]; fState(is); is.read (buffer,len); fState(is); is.close(); tofstream os; fState(os); os.open (outPATH, ios_base::binary ||ios_base::out); fState(os); os.write(buffer,len); fState(os); os.close(); delete[] buffer; }
int _tmain(int argc, _TCHAR *argv[]) { PrepareForTestBinary(_T("D:\\!binary\\1\\11")); TestBinary(_T("D:\\!binary\\1\\11"),_T("D:\\!binary\\1\\22")); system("pause"); return 0; }
При этом такой способ никаких проблем не даёт (но и проблем моих с парсом не решает):
void TestBinary_bufferExch(tstring inPATH,tstring outPATH) { tifstream is; tofstream os; is.open (inPATH, ios_base::binary || ios_base::in ); os.open (outPATH,ios_base::binary ||ios_base::out); os << is.rdbuf(); is.close(); os.close(); }
Сопутствующие вопросы:
Как оптимально вырезать из потока все символы '0x00' ? Пока ничего умнее не придумал, как в цикле посимвольно сравнивать и все отличные от '0x00' писать в другой буфер(или поток). Как вообще правильно читать поток, содержимое и формат которого не известны? Прошу ткнуть в мало-мальски грамотный парсер(код пощупать).
Обновление
Пробовал даже так, никаких изменений.
void TestBinary(tstring inPATH,tstring outPATH) { LONGLONG len = 0; TCHAR * buffer = 0; tifstream is; fState(is); is.open (inPATH, ios_base::binary ||ios_base::in ); fState(is); is.seekg (0, ios::end); len = is.tellg(); is.seekg (0, ios::beg); buffer = new TCHAR [len]; memset(buffer,0,len); fState(is); is.read (buffer,len); fState(is); is.close(); tofstream os; fState(os); os.open (outPATH, ios_base::binary ||ios_base::out); fState(os); os.write(buffer,len); fState(os); os.close(); delete[] buffer; }
Обновление 2
Провёл доп. исследования. Проблема возникает только при наличии в файле 0x0D 0x0A (endl помещённый в поток). При наличии '\0' (0x00) проблема не возникает.


Ответ

В вашем коде мне кажется я вижу одну неточность. "Побитовое ИЛИ" должно писаться через один символ | (ios_base::binary |ios_base::in). В вашем случае это операция "логического ИЛИ" и результат его скорее всего равен 1 для обоих файлов.

пятница, 28 июня 2019 г.

Прочитать с середины файл без чтения его начала на Rust'е

let f = File::open("file").unwrap(); let reader = BufReader::new(f).seek(io::SeekFrom::Start(2)); for b in reader.iter().next() { println!("{}", b); }
Выводит то, что находится внутри io::SeekFrom::Start, т.е. 2.


Ответ

Какой-то странный цикл у вас. По идее должно быть как-то так:
let f = File::open("file").unwrap(); let mut reader = BufReader::new(f); reader.seek(io::SeekFrom::Start(2)).unwrap(); for b in reader.bytes() { println!("{}", b); }
Метод seek() возвращает Result, то есть новую позицию в файле. Он вызывается на &mut self, значит reader должен быть mut, иначе не заработает.
Что делает ваш код: вы открываете файл и смещаете указатель на 2 байта, сохраняя Result в reader. Потом вы преобразовываете Result в итератор с помощью iter() и вызываете на итераторе next(), получаете Option, равный Some(2). А потом по опции итерируете (Option<_> реализует IntoIterator, так что этому типу можно итерировать). Итератор весело выдаёт один элемент — 2.
Чтобы избежать подобных ошибок в будущем, внимательно читайте документацию на используемые трейты и типы: ни в трейте Read, ни в типе BufReader нет метода iter(), однако в Read есть метод bytes(), который вам был нужен. А вот метод Seek::seek возвращает Result. Кроме того стоит больше прочитать про интерфейс итераторов, так как вы, судя по всему, до конца не поняли эту идею, раз вызываете на итераторе метод next() явно.

четверг, 13 июня 2019 г.

Запись string в бинарый файл . С++

Нужна помощь.
У меня есть класс с полями типа: string, int и float; Как мне занести данные даного класса в бинарный файл?
Пример кода:
class foo { string Name; int Age; public:
void show() { cout << "Name = " << Name << endl; cout << "Age = " << Age << endl; } };
int main() { foo obj("Something Name", 10); foo obj2;
ofstream file("file.bin", ios::binary | ios::app); file.write((char *)(&obj), sizeof(obj)); file.close();
ifstream file2("file.bin", ios::binary); file2.read((char *)(&obj2), sizeof(obj2)); file2.close();
obj2.show();
return 0; }
В результате работы программы выскакивает ошибка.


Ответ

Этот вопрос обсуждался, но раз вы спрашиваете как, а не почему :), то примерно так:
class foo { string Name; int Age; public:
void show() { cout << "Name = " << Name << endl; cout << "Age = " << Age << endl; }
void write(ostream& os) { os.write((char*)&Age, sizeof(Age)); // Запись POD-члена size_t len = Name.length()+1; // Длина с нулевым байтом os.write((char*)&len, sizeof(len)); // Запись длины os.write((char*)Name.c_str(),len); // Запись данных }
void read(istream& in) { in.read((char*)&Age,sizeof(Age)); // Чтение POD-члена size_t len; // Переменная для длины in.read((char*)&len, sizeof(len)); // Чтение длины записанной строки char * buf = new char[len]; // Выделение буфера для чтения in.read(buf,len); // Чтение (с нулевым байтом) Name = buf; // Присвоение считанной строки члену delete[]buf; // Освобождение памяти } };
А дальше -
ofstream file("file.bin", ios::binary | ios::app); obj.write(file);
Ну и, соответственно, read
Это - наброски без проверки ошибок, попроще - чтоб была понятна идея. Можно читать прямо в строку, функцию write нужно сделать константной etc etc... но главное, надеюсь, ясно?

пятница, 26 апреля 2019 г.

С++. Дважды прочитать файл. Библиотека fstream

Доброго времени суток.
Возник такой вопрос. Как в библиотеке fstream дважды прочитать файл без его закрытия?
Нашел функции rewind() и fseek(file,0L,SEEK_SET), но они отказываются работать, если открывать файл не функцией fopen из библиотеки stdio.h
Есть ли альтернатива для библиотеки fstream?


Ответ

Посмотрите на seekg(). И, если нарвались на конец файла или иные неприятности - не забывайте сбросить состояние ошибки с помощью clear()