Почему я не могу прочитать двоичные данные fstream с оператором››?

Если я сделаю что-то вроде следующего:

ifstream file;
file.open("somefile", ios::binary);

unsigned int data;

file >> data;

Мой поток всегда будет устанавливать failbit, а data останется неинициализированным. Однако, если вместо этого я читаю char или unsigned char, с потоком все в порядке. perror() говорит мне "результат слишком велик".

Единственное, что я увидел в Google, это предложение о том, что operator>> не следует использовать для двоичных данных (предпочтительнее read()), но я считаю, что этот оператор чище и проще в использовании — и он не требует приведения всего.

Может ли кто-нибудь объяснить эту проблему?


person Galf    schedule 11.11.2010    source источник


Ответы (2)


оператор извлечения iostream (>>) пытается интерпретировать числовые строки, разделенные пробелами, а не двоичные данные. Существует множество различных способов кодирования целого числа без знака в двоичной форме (например, 32-разрядное дополнение до 2 в порядке байтов с прямым порядком байтов). Вот почему вы должны использовать read/write для работы с такими бинарными буферами.

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

person Judge Maygarden    schedule 11.11.2010

Это должно быть сделано, как описано вами. Однако стандартные дизайнеры C++ не очень элегантны. На самом деле, в дизайне C++ много недостатков, даже в C++11 и C++14 есть много недостатков.

Идеальный дизайн C++ должен быть таким:

1.Для текстового файла:

ifstream fin_txt("input.txt");
int i;
float j;
double k;
fin_txt >> i >> j >> k;

Это будет считывать 3 строки и анализировать их на целое число, число с плавающей точкой и двойное число и сохранять их в i, j и k соответственно.

2.Для бинарного файла:

ifstream fin_txt("input.bin", ios::binary);
int i;
float j;
double k;
fin_txt >> i >> j >> k;

Это будет считывать 4/8 байтов (в зависимости от того, является ли int 32-битным или 64-битным), 4 байта и 8 байтов двоичных данных и сохранять их в i, j и k соответственно.

К сожалению, текущий дизайн должен сообщать об ошибке для случая 2. Возможно, этого можно добиться в C++22.

person xuancong84    schedule 13.04.2016
comment
У вас есть причина, по которой это так, в вашем ответе: в зависимости от того, является ли int 32-битным или 64-битным. В настоящее время код, использующий <iostreams>, является переносимым, а ваше предложение — нет. - person Caleth; 31.08.2017
comment
Для @Caleth, ну, как я уже сказал, это еще один дефект дизайна в стандартном C++, он должен различать int32 и int64, а не только int, который может быть 32-битным или 64-битным, может быть, 128-битным в будущем . Детерминированность размера поля int отличается от других (char=8 бит, long=32 бита, long long=64 бита, float=32 бита, double=64 бита). Чтобы решить эту проблему, мы можем просто определить int32 и int64 соответственно, и выдается ошибка времени выполнения, если для двоичного файла задан недетерминированный тип размера поля, то есть fin_txt ›› i; // выдает ошибку, fin_txt ›› (int32)i; // корректно компилируем - person xuancong84; 18.12.2018
comment
ios::binaryios::text) не для этого. Некоторые платформы различают текстовый режим и двоичный режим в том, как они представляют файлы с символами конца строки. Флаги ios только имеют дело с этим. - person Caleth; 18.12.2018
comment
@Caleth тогда может быть текстовый поток с операторами›› и ‹‹, выполненный с использованием форматирования текста и двоичного потока, другого класса, с ›› выполненным как двоичная запись - person Adam; 22.12.2018