Вставка и извлечение чтения / записи двоичных данных против текста - PullRequest
6 голосов
/ 22 ноября 2011

Я пытался читать iostreams и понимать их лучше. Время от времени я подчеркиваю, что вставки (<<) и экстракторы (>>) предназначены для текстовой сериализации. Это несколько мест, но эта статья является хорошим примером:

http://spec.winprog.org/streams/

За пределами вселенной <iostream> существуют случаи, когда << и >> используются потоковым способом , но не подчиняются никаким текстовым соглашениям. Например, они записывают двоичные данные, когда они используются Qt's QDataStream:

http://doc.qt.nokia.com/latest/qdatastream.html#details

На уровне языка операторы << и >> принадлежат вашему проекту для перегрузки (следовательно, то, что делает QDataStream, явно приемлемо). Мой вопрос заключается в том, считается ли это плохой практикой для тех, кто использует <iostream>, использовать операторы << и >> для реализации двоичного кодирования и декодирования. Существуют ли (например) какие-либо ожидания, что при записи в файл на диске этот файл должен быть доступен для просмотра и редактирования в текстовом редакторе?

Всегда ли следует использовать имена других методов и основывать их на read() и write()? Или текстовые кодировки следует рассматривать просто как поведение по умолчанию, которое классы, интегрирующиеся со стандартной библиотекой iostream, могут игнорировать?


ОБНОВЛЕНИЕ Ключевой вопрос терминологии в этом вопросе, по-видимому, заключается в различении операций ввода-вывода, которые «отформатированы» и «не отформатированы» (в отличие от терминов «текстовый» и «двоичный»). Я нашел этот вопрос:

запись двоичных данных (std :: string) в std :: ofstream?

В нем есть комментарий от @ TomalakGeret'kal, в котором говорится «Я бы не хотел использовать << для двоичных данных в любом случае, так как мой мозг читает их как« форматированный вывод », а это не то, что вы делаете. Опять же, это совершенно справедливо, но я бы не стал так путать свой мозг. "</em>

Принятый ответ на вопрос говорит, что все в порядке, если вы используете ios::binary. Это, кажется, поддерживает сторону «нет ничего плохого в этом» ... но я все еще не вижу авторитетного источника по этому вопросу.

Ответы [ 3 ]

9 голосов
/ 29 ноября 2011

На самом деле операторы << и >> являются операторами сдвига битов;строго говоря, использование их для ввода / вывода уже неправильно.Однако такое неправильное использование примерно столько же, сколько и сама перегрузка операторов, и в настоящее время наиболее часто их используют операции ввода-вывода, поэтому они широко рассматриваются как операторы ввода / вывода ввода-вывода.Я почти уверен, что если бы не было прецедента iostreams, никто бы не использовал эти операторы для ввода-вывода (особенно с C ++ 11, в котором есть переменные шаблоны, решая основную проблему, которая с помощью этих операторов решалась для iostreams, внамного чище способ).С другой стороны, с языковой точки зрения, перегруженные operator<< и operator>> могут означать то, что вы хотите, чтобы они имели в виду.

Таким образом, вопрос сводится к тому, что было бы приемлемым использование этих операторов.Для этого, я думаю, нужно различать два случая: во-первых, новые перегрузки, работающие с классами iostream, и, во-вторых, новые перегрузки, работающие с другими классами, возможно, предназначенные для работы подобно iostreams.

Давайте рассмотрим первые новые операторы назанятия iostream.Позвольте мне начать с наблюдения, что все классы iostream - это форматирование (и обратный процесс, который можно назвать «деформатированием»; «лексирование») ИМХО здесь не совсем подходит, поскольку экстракторы не определяют тип, но только попытайтесь интерпретировать данные в соответствии с указанным типом).Классы, ответственные за фактический ввод / вывод необработанных данных, являются streambufs.Однако обратите внимание, что правильный двоичный файл - это , а не файл, в который вы просто записываете внутренние необработанные данные.Как и текстовый файл (на самом деле даже больше), двоичный файл должен иметь четко определенную кодировку содержащихся в нем данных.Особенно, если файлы должны быть прочитаны в разных системах.Поэтому концепция форматированного вывода имеет смысл также для двоичных файлов;отличается только форматирование (например, запись предварительно определенного числа байтов с самым старшим первым для целочисленного значения).

Сами iostreams являются классами, которые предназначены для работы с текстовыми файлами, то естьна файлах, содержание которых интерпретируется как текстовое представление данных.Многие встроенные функции оптимизированы для этого и могут вызывать проблемы при использовании в двоичных файлах.Очевидным примером является то, что по умолчанию пробелы пропускаются перед попыткой ввода.Для двоичного файла это было бы явно неправильным поведением.Кроме того, использование локалей не имеет смысла для двоичных файлов (хотя можно утверждать, что может существовать «двоичная локаль», но я не думаю, что локали, определенные для iostreams, обеспечивают подходящий интерфейс для этого).Поэтому я бы сказал, что написание двоичного operator<< или operator>> для классов iostream было бы неправильным.

Другой случай, когда вы определяете отдельный класс для двоичного ввода / вывода (возможно, для повторного использования слоя streambuf для выполненияфактический ввод / вывод).Поскольку сейчас мы говорим о разных классах, приведенная выше аргументация больше не применяется.Таким образом, теперь возникает вопрос: должны ли operator<< и operator>> на вводе / выводе рассматриваться как «операторы вставки / извлечения текста» или, в более общем смысле, как «операторы вставки / извлечения отформатированных данных»?Стандартные классы используют их только для текста, но тогда вообще не существует стандартных классов для вставки / извлечения двоичного ввода-вывода, поэтому стандартное использование не может различить их.

Лично я бы сказал, что двоичныйвставка / извлечение достаточно близки к текстовой вставке / извлечению, что такое использование оправдано.Обратите внимание, что вы также можете создавать значимые двоичные манипуляторы ввода / вывода, например, bigendian, littleendian и intwidth(n), чтобы определить формат, в котором должны быть выведены целые числа.

Помимо этого, есть также использование этих операторов для вещей, которые на самом деле не являются вводом-выводом (и где вы даже не думаете об использовании слоя streambuf), например, чтение или вставка в контейнер.На мой взгляд, это уже является неправильным использованием операторов, потому что там данные не переводятся в другой формат или из него.Он просто хранится в контейнере.

4 голосов
/ 22 ноября 2011

Абстракция iostreams в стандарте - это абстракция форматированный поток данных; нет поддержки для любого нетекстового формата. Это абстракция iostreams. В этом нет ничего плохого определение другого класса потока, чья абстракция представляет собой двоичный формат, но выполнение этого в iostream, скорее всего, нарушит существующий код, а не Работа.

3 голосов
/ 28 ноября 2011

Перегруженные операторы >> и << выполняют форматированный ввод-вывод. Остальные функции ввода-вывода (положить, получить, прочитать, написать и т. Д.) Выполняют неформатированный ввод-вывод. Неформатированный ввод-вывод означает, что библиотека ввода-вывода принимает только буфер, последовательность символов без знака для своего ввода. Этот буфер может содержать текстовое сообщение или двоичное содержимое. Приложение отвечает за интерпретацию буфера. Однако форматированный IO будет учитывать локаль. В случае текстовых файлов, в зависимости от среды, в которой выполняется приложение, в операциях ввода / вывода может происходить специальное преобразование символов, чтобы адаптировать их к системному формату текстовых файлов. Во многих средах, таких как большинство систем на основе UNIX, нет разницы, чтобы открыть файл в виде текстового файла или двоичного файла. Обратите внимание, что вы можете перегрузить операторы >> и << для ваших собственных типов. Это означает, что вы можете применять форматированный ввод-вывод без информации о локали к вашим собственным типам, хотя это немного сложно. </p>

...