C#/.NET — пользовательские форматы двоичных файлов — с чего начать?

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

Вопрос

Мне нужно иметь возможность хранить некоторые данные в специальном формате двоичного файла.Я никогда раньше не разрабатывал свой собственный формат файла.Это должен быть удобный формат для путешествий между мирами C#, Java и Ruby/Perl/Python.

Начнем с того, что файл будет состоять из записей.Поле GUID и поле пакета JSON/YAML/XML.Я не уверен, что использовать в качестве разделителей.Запятая, табуляция или новая строка кажутся слишком хрупкими.Что делает Excel?или форматы OpenOffice до XML?Если вы используете символы ASCII 0 или 1.Не уверен, с чего начать.Есть какие-нибудь статьи или книги по этой теме?

Позже этот формат файла может быть расширен за счет включения «раздела заголовка».

Примечание:Начнем с того, что я буду работать в .NET, но мне бы хотелось, чтобы этот формат можно было легко переносить.

ОБНОВЛЯТЬ:
Обработка «пакетов» может быть медленной, но навигация внутри формата файла — нет.Поэтому я думаю, что XML не обсуждается.

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

Решение

Я попытаюсь добавить несколько общих советов по созданию переносимого формата двоичных файлов.

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

Теперь подсказки:

  1. Решите, что делать с порядок байтов.Хороший и простой способ — решить это раз и навсегда.Предпочтительно выбирать вариант с прямым порядком байтов при использовании на обычном ПК (то есть x86) для сохранения преобразований (производительности).

  2. Создавать заголовок.Да, всегда иметь заголовок — это хорошая идея.Первые байты файла должны подсказать вам, с каким форматом вы возитесь.

    • Начните с магии, чтобы распознать ваш формат (строка ASCII подойдет).
    • Добавить версию.Версию вашего формата файла не помешает добавить и это позволит вам сделать обратную совместимость позже.
  3. Наконец, добавьте данные.Теперь формат данных будет конкретным и всегда будет основываться на ваших конкретных потребностях.По сути, данные будут храниться в двоичном образе некоторой структуры данных.Структура данных — это то, что вам нужно придумать.

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

Кроме того, вы можете использовать TLV (Тип-Длина-Значение) концепция прямой совместимости.

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

Как насчет использования «буферов протокола»?Разработанный как эффективный, переносимый, устойчивый к версиям двоичный формат общего назначения, он предоставляет вам C++, Java и Python в библиотека Google, и C#, Perl, Ruby и другие в общественные порты?

Обратите внимание, что у Guid нет определенного типа данных, но вы можете представить его как сообщение с (по сути) byte[].

Обычно для работы .NET я бы рекомендовал protobuf-net (но как автор я несколько предвзят) - однако, если вы собираетесь использовать другие языки позже, вам может быть лучше (в долгосрочной перспективе), используя Jon's dotnet-protobufs;это даст вам знакомый API для всех платформ (где protobuf-net использует идиомы .NET).

Каждый символ ASCII 0 или 1 занимает несколько бит (как и любой другой символ), поэтому, если вы храните его таким образом, ваш «двоичный» файл будет в несколько раз больше, чем должен быть.Текстовый файл из нулей и единиц - это не совсем двоичный файл :)

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

Однако, если вас больше всего интересует переносимость, я вообще рекомендую не использовать двоичный формат. XML создан специально для решения проблем переносимости и совместимости.Это многословный и весомый формат файла, но это компромисс, на который вы идете, чтобы решить эти проблемы за вас. Если удобочитаемый формат не обсуждается, Ответ Марка это путь.Не нужно изобретать велосипед портативности!

Это зависит от того, какой тип данных вы будете записывать в двоичный файл и какова цель двоичного файла.Являются ли они объектами класса или просто записывают данные?Если это данные записи, я бы рекомендовал поместить их в формат xml.Таким образом, вы можете включить проверку схемы, чтобы убедиться, что файл соответствует вашим стандартам.В Java и .NET существуют инструменты для импорта и экспорта данных из/в формат xml.

Предположим, ваш формат:

    struct Format
    {
        struct Header // 1
        {
            byte a;
            bool b1, b2, b3, b4, b5, b6, b7, b8;
            string name;
        }
        struct Container // 1...*
        {
            MyTypeEnum Type;
            byte[] data;
        }
    }

    enum MyTypeEnum
    {
        Sound,
        Video,
        Image
    }

Тогда у меня будет последовательный файл с:


байт // а

байт // б

int // размер имени

char[] // имя (размер которого указан выше, помните, что в .NET символ имеет длину 16 бит)

int // тип MyTypeEnum

int // размер данных

byte[] // данные (размер которых указан выше)


Затем вы можете повторять последние три строки столько, сколько захотите.

Для чтения вы используете BinaryReader который поддерживает чтение байтов, целых чисел и серий байтов.Существует также BinaryWriter.

Кроме того, помните, что Microsoft .NET (то есть на машине Windows/Intel) имеет прямой порядок байтов.Так и BinaryReader и BinaryWriter.

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