Что поместить в заголовок файла двоичных данных

StackOverflow https://stackoverflow.com/questions/416436

  •  03-07-2019
  •  | 
  •  

Вопрос

У меня есть симуляция, которая считывает большие файлы двоичных данных, которые мы создаем (от 10 до 100 ГБ).Мы используем двоичный код из соображений скорости.Эти файлы зависят от системы и преобразуются из текстовых файлов в каждой используемой нами системе, поэтому меня не беспокоит переносимость.В настоящее время файлы представляют собой множество экземпляров структуры POD, написанной с помощью fwrite.

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

Это было полезно?

Решение

По моему опыту, размышления о том, какие данные вам понадобятся, — это всегда пустая трата времени.Важно структурировать свой метаданные таким образом, чтобы его можно было расширить.Для XML-файлов это просто, но двоичные файлы требуют немного большего размышления.

Я предпочитаю хранить метаданные в структуре в КОНЦЕ файла, а не в его начале.Это имеет два преимущества:

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

Самый простой нижний колонтитул с метаданными, который я использую, выглядит примерно так:

struct MetadataFooter{
  char[40] creatorVersion;
  char[40] creatorApplication;
  .. or whatever
} 

struct FileFooter
{
  int64 metadataFooterSize;  // = sizeof(MetadataFooter)
  char[10] magicString;   // a unique identifier for the format: maybe "MYFILEFMT"
};

После необработанных данных записывается нижний колонтитул метаданных, а затем нижний колонтитул файла.

При чтении файла ищите до конца — sizeof(FileFooter).Прочтите нижний колонтитул и проверьте MagicString.Затем выполните поиск обратно в соответствии с метаданнымиFooterSize и прочитайте метаданные.В зависимости от размера нижнего колонтитула файла вы можете использовать значения по умолчанию для отсутствующих полей.

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

Другие советы

Для больших двоичных файлов я бы серьезно посмотрел на HDF5 (Google для него). Даже если это не то, что вы хотите принять, это может указать вам несколько полезных указаний при разработке собственных форматов.

Для больших двоичных файлов, в дополнение к номеру версии, я склонен указывать количество записей и CRC, причина в том, что большие двоичные файлы гораздо более склонны к усечению и / или повреждению с течением времени или во время передачи, чем меньшие. Недавно, к своему ужасу, я обнаружил, что Windows не справляется с этим вообще, так как я использовал explorer для копирования около 2 ТБ из нескольких сотен файлов на подключенное устройство NAS и обнаружил, что 2-3 файла в каждой копии были повреждены (не полностью копируется).

Идентификатор типа файла был бы полезен, если позже у вас будут другие структуры, записанные в двоичные файлы. Возможно, это может быть короткая строка, чтобы вы могли посмотреть в файле (через шестнадцатеричный редактор), что он содержит.

Если они такие большие, я бы зарезервировал здоровый кусок (64 КБ?) пространства в начале файла и поместил туда метаданные в формате XML с последующим символом конца файла (Ctrl-Z для DOS / Windows, Ctrl-D для Unix?). Таким образом, вы можете легко анализировать и анализировать метаданные с помощью широкого набора инструментов для XML.

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

Одним из больших преимуществ HDF5, как упомянул @highpercomp, является то, что вам не нужно беспокоиться об изменениях в формате структуры, если у вас есть какое-то соглашение о том, какие имена и типы данных. Имена структур и типы данных хранятся в самом файле, так что вы можете передать свой код на C вдребезги, и это не имеет значения, вы все равно можете извлечь данные из файла HDF5. Это позволяет вам меньше беспокоиться о формате данных и больше о структуре данных, т. Е. Меня не волнует последовательность байтов, это проблема HDF5, но я заботиться об именах полей и т. п.

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

@rstevens сказал «идентификатор для типа файла» ... хороший совет. Обычно это называется магическим числом и в файле не является термином злоупотребления (в отличие от кода, где это термин злоупотребления). По сути, это некоторое число - обычно не менее 4 байтов, и я обычно гарантирую, что хотя бы один из этих байтов не является ASCII - что вы можете использовать для проверки того, что файл того типа, который вы ожидаете, с низкой вероятностью путаницы , Вы также можете написать правило в / etc / magic (или локальный эквивалент), чтобы сообщить, что файлы, содержащие ваш магический номер, относятся к вашему особому типу файлов.

Вы должны указать номер версии формата файла. Тем не менее, я бы порекомендовал не использовать номер SVN кода. Ваш код может измениться, если формат файла не изменился.

Помимо любой информации, необходимой для управления версиями схемы, добавьте сведения, которые могут оказаться полезными при устранении неполадок.Например:

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

Мы считаем, что это очень полезно (а) для получения информации, которую в противном случае пришлось бы просить клиента предоставить, и (б) получения правильной информации — удивительно, как много клиентов сообщают, что они используют версию программного обеспечения, отличную от той, которую претензии к данным!

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

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

Как показывает мой опыт настройки телекоммуникационного оборудования и обновления прошивки, вам действительно нужно всего лишь несколько предопределенных байтов в начале (это важно), которое начинается с версии (фиксированной части заголовка).Остальная часть заголовка не является обязательной, указав правильную версию, вы всегда можете показать, как ее обрабатывать.Здесь важно то, что вам лучше разместить «переменную» часть заголовка в конце файла.Если вы планируете операции с заголовком без изменения самого содержимого файла.Также это упрощает операции добавления, которые должны пересчитывать часть заголовка переменной.

Приятно иметь функции для заголовка фиксированного размера (в начале):

  • Общее поле длины (включая заголовок).
  • Что-то вроде CRC32 (включая заголовок).

Хорошо, для переменной части XML или какой-нибудь довольно расширяемый формат в заголовке — хорошая идея, но действительно ли это необходимо?У меня был большой опыт кодирования ASN...в большинстве случаев его использование было превышено.

Что ж, возможно, у вас появится дополнительное понимание, когда вы посмотрите на такие вещи, как формат TPKT, который описан в РФК 2126 (глава 4.3).

Если вы помещаете номер версии в заголовок, вы можете изменить эту версию в любое время, когда вам нужно изменить структуру POD или добавить новые поля в заголовок.

Так что не добавляйте вещи в заголовок сейчас, потому что это может быть интересно. Вы просто создаете код, который нужно поддерживать, но он не имеет реальной ценности.

Для больших файлов может потребоваться добавить определения данных, чтобы формат файла стал самоописываться.

Мой вариант сочетает в себе подходы Родди и Джейсона С.

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

1) Поместите поле длины в начало вашего файла, чтобы вы знали длину метаданных в конце, а не предполагали фиксированную длину. Таким образом, чтобы получить метаданные, вы просто читаете это начальное поле фиксированной длины, а затем получаете блоб метаданных из конца файла.

2) Используйте XML, YAML или JSON для метаданных. Это особенно полезно / безопасно, если метаданные добавляются в конце, потому что никто, читающий файл, не будет автоматически думать, что это все XML, только потому, что он начинается с XML.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top