Есть ли опасность записи сырых байтов в файл? [закрыто]

12

Я работаю над проблемой в Программировании Жемчужин - в частности, над реализацией программы, которая сортирует файл, содержащий не более 10 000 000 целых чисел (Столбец 1, Проблема 3). Поскольку в книге не указано, как данные должны храниться в файле, я рассматриваю возможность хранения целых чисел в виде необработанных байтов (есть некоторые другие ограничения, которые делают необработанные байты хорошим вариантом). Я никогда раньше не работал на таком низком уровне, поэтому я хочу знать, есть ли что-то опасное, на что я должен обратить внимание. Нужно ли беспокоиться о случайном использовании какой-либо последовательности конца файла, когда я, например, записываю необработанные байты в файл?

Редактировать:

Теперь я понимаю, насколько широк мой вопрос. Я действительно имел в виду проблемы более катастрофического характера, такие как случайная перезапись других файлов на диске. Извините, я не был яснее изначально.

Дрейк Собания
источник
6
Обратите внимание, что «Программирование жемчуга» - очень старая книга; Вы можете легко прочитать целые 10 ^ 7 целых чисел в памяти на современном настольном компьютере, выполнить сортировку и записать ее снова. Чтобы получить первоначальный смысл этой главы, ограничьте сумму, которую вы читаете в любое время, до доли от общего числа. Или увеличьте размер файла примерно до 10 ^ 10 целых чисел.
Калеб
3
На самом деле, когда я слышу слово «опасный», я думаю о вещах, которые взрывают мой компьютер, удаляют мои банковские счета или что-то в этом роде. И я думаю, что, скорее всего, можно предположить, что - пока ваша программа не используется для управления Airbus или силовой установкой - ничего действительно «опасного» не произойдет, когда вы попробуете то, что имеете в виду.
Док Браун
2
@delnan Несколько лет назад, когда миф о персонаже EOF был в моде, я вспоминаю системы защиты от копирования, основанные на «копировании до символа EOF», как это делали многие программы копирования того времени. Некоторые программы помещают дополнительные данные, которые они будут проверять после маркера EOF соответствующего текстового файла, но до выделенного конца файла. Программа копирования не будет копировать дополнительные данные, подтверждающие чистую установку ... ааа ... ностальгия.
Опасность? Например, «взорвется ли мой компьютер, если я это сделаю»? Нет.
jwenting

Ответы:

11

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

Файловая система предназначена для обработки любой последовательности байтов.

чокнутый урод
источник
2
+1 за последнюю строку. Я не уверен, что большая / маленькая проблема - единственная проблема - ОП может, например, запутаться, где границы между целыми числами. Но хороший ответ в любом случае.
Калеб
27

Нет, на самом деле это то, сколько форматов файлов работает. Типичные примеры бинарных файлов, таких как это, включают изображения и музыкальные / аудио файлы.

Чтобы сохранить целостность файла и данных, прочитанных из него, обязательно следуйте этим рекомендациям:

  • Всегда открывайте файл (чтение или запись), используя один и тот же режим: текстовый или двоичный. Основным отличием является то, что текстовый режим заботится о новых строках и может «разбивать» символы новой строки при чтении файла (в зависимости от конкретной используемой библиотеки). Текстовый режим также может выполнять переводы в Юникоде, которые, вероятно, задушат данные, не относящиеся к Юникоду.
  • При чтении нестроковых данных обязательно читайте, используя тот же тип данных, что и при записи. Например, если первые четыре байта файла являются описательным целым числом, обязательно прочитайте и запишите, используя метод, который принимает / предоставляет целое число, чтобы гарантировать, что он обрабатывается последовательно. Один и тот же тип данных может иметь разный размер на разных машинах, и смешивание типов данных на одной и той же машине может также изменить смысл данных (например, интерпретировать бит в середине более длинного целого как бит знака).
  • Endianness: если используемая вами библиотека не справляется с этим последовательно, вам, возможно, придется обрабатывать ее самостоятельно. Например, Java всегда использует сетевой порядок байтов (с прямым порядком байтов) для многобайтовых типов. C и C ++ используют все, что решит разработчик библиотеки, как правило, то же самое, что и процессор (с прямым порядком байтов в Intel, в большинстве других байтов). Если это быстрое упражнение в одной системе, то это не так важно, но все же хорошая привычка обращать на это внимание и при необходимости кодировать его.

Конкретные детали могут различаться в зависимости от платформы, платформы и языка, но это должно охватывать основные «ошибки» с файловым вводом / выводом.


источник
3
Дополнительный момент для нестроковых данных: убедитесь, что вы используете одинаковое количество байтов для каждого типа. В C и C ++ intможет быть от 2 до 8 или более байтов (на самом деле октеты).
Барт ван Инген Шенау
Это неявно включено в мою вторую точку, например, 32 v. 64-битное целое число. Это были бы разные типы данных.
Вы можете сделать это явным. Не очевидно, что intна двух разных машинах могут рассматриваться разные типы данных.
Барт ван Инген Шенау
9

В дополнение ко всем уже упомянутым ошибкам, если вы создаете новый двоичный формат файла, а не считываете и записываете данные в существующем формате, абсолютно необходимо включить заголовок файла : блок данных в самом начале файла, который однозначно определяет формат файла и записывает любые метаданные, которые могут потребоваться.

Хорошие заголовки файлов включают как минимум три вещи:

  • « Магическое число », по крайней мере, четыре байта. Магическое число ДОЛЖНО быть rfc2119 быть самыми первыми N байтами в файле, НЕ ДОЛЖНО использоваться для любого другого формата файла, который вы можете найти, и ДОЛЖНО содержать по крайней мере один байт, который не является печатаемым символом ASCII. Смотрите спецификацию PNG, чтобы узнать, как создать действительно тщательное магическое число. Посмотрите исходный код file(1)команды для базы данных существующих магических чисел, которая является настолько полной, насколько вы, вероятно, найдете.

    Смысл магического числа в том, чтобы однозначно пометить внутриполосный файл его форматом. Если вы не включили магическое число или это не первое, что есть в файле, вы рискуете из-за того, что программы ошибочно идентифицируют ваш файл как файл другого типа, что приводит к потере данных, обнаружению вирусов и другим подобным катастрофы.

  • Указание версии формата файла. Даже если вы думаете, что вам никогда не придется кардинально пересматривать формат файла, задайте следующие два байта после магического числа 00 00и задокументируйте, что это 16-битный номер версии с определенным порядком байтов (в зависимости от того, что вам нравится, но выберите один и придерживаться его по всему файлу ) и будет увеличиваться, если значение последующих данных радикально изменится. Ваше будущее я будет вам благодарен.

    (Спецификация PNG здесь использует другой маршрут, определяя, что форматы чанков заморожены, и что все будущие изменения в формате будут принимать форму новых типов чанков. Это также верно, но я рекомендую простой подход «магическое число + номер версии» для новички в обработке двоичных данных. Люди, разработавшие PNG, опирались на многолетний опыт работы с форматами изображений.)

  • Какой-то механизм встраивания произвольных метаданных в файл. Это может быть так же просто, как если бы следующие два байта представляли собой 16-битное смещение от конца заголовка до начала фактических данных, а все промежуточное значение должно интерпретироваться как пары ключ-значение UTF-8, как в RFC 822 (то есть " Tag: value\n" - если вы идете по этому маршруту, я рекомендую не допускать складывания длинных линий). Опять же, PNG значительно умнее.

zwol
источник
Нет необходимости создавать свой собственный формат файла ... просто храните данные в виде изображения. Возможно, вам придется изменить размерность (например, 10k x 1k), чтобы она поддерживалась. Или вы можете использовать FITS . Если ваши данные более сложны, чем просто один массив, вы можете использовать HDF , CDF или NetCDF .
Джо
Я бы предложил сделать это простым. 256 различных версий будет достаточно, и если нет, дополнительные версии могут быть разработаны как подрывные версии версии 255. Аналогично для метаданных, достаточно добавить их в версию, когда они действительно необходимы. @Joe Image ??? Вы избегаете путаницы в формате, путая всех заранее!
Maaartinus
@maaartinus Создание поля версии в два байта вынуждает дизайнера формата фиксировать сразу. Место для метаданных всегда должно быть в версии 0 двоичного формата, в противном случае вы получите ужасные кладжи, такие как ID3. У меня есть большое сочувствие к логике спецификации PNG в отношении расширяемости с помощью новых типов чанков, а не выпусков форматной версии. Тем не менее, файлы со структурой фрагментов несут в себе большую сложность, поэтому я не решаюсь рекомендовать их для простых случаев. Я был соблазн рекомендовать HDF как общий формат , который занимался с большим количеством уже этих вопросов.
zwol
2

Разные архитектуры имеют разные представления для целых чисел. Основной риск здесь заключается в сохранении байтового представления целого числа в машине A, а затем в попытке прочитать его обратно и интерпретировать содержимое как целые числа в машине B. Если машины A и B имеют разные размеры для целых чисел и / или различные порядковые номера , вы ' Скорее всего, вызовет неопределенное поведение (например, в C) или исключение.

Поскольку это всего лишь пример программирования, а не «настоящая» программа, на самом деле это не проблема. Если бы это была настоящая программа, использование собственного двоичного формата для конкретного приложения, как правило, не очень хорошая идея; есть более эффективные решения, такие как SQLite или форматы сериализации на основе строк, такие как JSON, YAML, XML и т. д. Для одиночных значений достаточно превратить их в строку; для простых списков вы можете сохранить одну строку на строку и просто разделить ввод на новые строки, когда вы прочитаете его обратно.

Doval
источник
Согласитесь в целом, но JSON или XML значительно увеличат размер файла, содержащего 10 ^ 7 чисел. Кроме того, они обычно читаются и анализируются одновременно, но рассматриваемая глава посвящена сортировке файлов, содержащих больше данных, чем вы можете уместить в доступной памяти.
Калеб
Это зависит от того, что вы делаете. Иногда снижение производительности SQL по сравнению с проверкой собственной разработки является существенным. В последний раз, когда я делал это, у меня были маленькие записи, и была большая вероятность, что я захочу соседей. Чтение большего блока с диска, как правило, почти ничего не стоит, поэтому, если мне нужна одна запись, я читаю 1000 в кеш. Мои записи почти наверняка были рядом друг с другом, с SQL головка диска отскакивала бы повсюду.
Лорен Печтел