Inserters и экстракторы чтение / запись двоичных данных против текста

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

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

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

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

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

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


обновление ключевой вопрос терминологии по - видимому, это различие ввода-вывода, которое "отформатировано" против "неформатировано" (в отличие от терминов "текстовый" против "двоичный"). Я нашел этот вопрос:

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

он имеет комментарий от @Tomalakgeret'KAL говоря " Я бы не хотел использовать

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

3 ответов


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

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

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

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

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

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

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


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


перегруженные операторы >> и > и