#c# #data-structures #binary #binary-data
#c# #структуры данных #двоичный #двоичные данные
Вопрос:
Мне любопытно, как приложения генерируют свои собственные данные, которые используются с самим приложением. Например, если вы возьмете файл сохранения любой компьютерной игры или какую-нибудь программу, которая генерирует двоичные данные, такие как PSD-файлы Photoshop или .torrent-файлы для приложений BitTorrent, я бы предположил, что все они специфичны для соответствующего приложения и что авторы этого приложения запрограммировали способ создания этих данных. Мой первый вопрос: это правда? Я на 99% уверен, что это двоичные данные, потому что при открытии PSD-файла или .torrent-файла в Notepad легко увидеть, что это не то, что может быть прочитано человеком…
Мой второй вопрос: если бы я хотел создать приложение, которое генерирует свои собственные данные в двоичном формате (без обычного текста или чего-либо, чем можно легко манипулировать), как бы я поступил с этими данными? Я могу смутно представить, как сгенерировать эти данные и сохранить их в файл в двоичном формате, но я действительно зациклен на том, как я буду обрабатывать эти данные, когда они снова понадобятся приложению. Поскольку этот тип данных не является обычным текстом и не может обрабатываться как строка или что-либо подобное, как получается, что приложения создают и обрабатывают / анализируют свои собственные двоичные данные (или любые двоичные данные вообще)?
Я, очевидно, вижу, что когда вы открываете PSD-файл, Photoshop открывается и отображает все, что содержится в PSD-файле. Но как многие приложения обрабатывают эти форматы? Я просто не вижу, как проанализировать эти конкретные данные (или двоичные данные в целом) и программно делать с ними то, что вы хотите.
Ответ №1:
Что ж, в качестве простого примера давайте возьмем растровые изображения.
Растровые изображения имеют стандартную файловую структуру, которая определяется заголовком info и заголовком файла.
В статье Википедии (ссылка:http://en.wikipedia.org/wiki/BMP_file_format ) вы увидите, что заголовок info имеет четко определенный формат, так же как и заголовок файла.
Каждый из них записывается как двоичный как есть, и читается как двоичный как есть. Затем фактически растровое изображение записывается как двоичное.
В других приложениях приложение может выбрать пользовательский формат обычного текста, и в этом случае оно должно быть записано согласованным образом или иметь некоторую поддержку управления версиями, чтобы вы могли использовать более новые функции в файле.
Посмотрите на сериализацию, хотя это довольно широкая тема, и существует множество подходов к этому.
Редактировать: Вот пример кода (не оптимальный) для чтения (или записи, с правильными изменениями) в растровых изображениях:
// Tell visual studio to align on 2-byte boundary
// Necessary so if you write to file, it only writes 14 bytes and not 16.
#pragma pack(2)
struct BMIH
{
short bfType;
long bfSize;
short bfReserved0;
short bfReserved1;
long bOffbits;
};
#pragma pack(8)
struct BMFH
{
long biSize;
long biWidth;
long biHeight;
short biPlanes;
short biBitCount;
long biCompression;
long biImageSize;
long biXPelsPerMeter;
long biYPelsPerMeter;
long biClrUsed;
long biClrImportant;
};
BMIH infoheader;
BMFH fileheader;
std::fstream file(filename.c_str(), std::ios::in | std::ios::binary);
// Read in info and file headers
file.read((char *) amp;infoheader, sizeof(infoheader));
file.read((char *) amp;fileheader, sizeof(fileheader));
// Calculate size of image
int size = fileheader.biHeight * fileheader.biWidth;
int bytes = size * fileheader.biBitCount / 8;
// Read in the image to a buffer
unsigned char data = new unsigned char[bytes];
file.read((char *) td.data, bytes);
file.close();
Этот код на самом деле является радикальным упрощением и полностью игнорирует всевозможные проблемы, такие как то, что произойдет, если заголовки файла или данные повреждены, если файл не является неполным и т.д. Но это всего лишь доказательство концепции. #pragma на самом деле специфичны для Visual Studio для обеспечения правильного выравнивания заголовков.
Когда мы записываем это в файл, мы на самом деле не можем сказать «Хорошо, теперь запишите это целое число». Вместо этого мы хотим записать их в двоичном формате. Например, код, который вы могли бы (но не должны) использовать для его написания, будет выглядеть следующим образом:
// Assume for arguments sake these data structures came pre-filled
BMFH fileheader;
BMIH infoheader;
unsigned char *data;
int size = fileheader.biHeight * fileheader.biWidth;
int bytes = size * fileheader.biBitCount / 8;
std::fstream file("MyImage.bitmap", std::ios::out | std::ios::binary);
file.write((char *) amp;infoheader, sizeof(BMIH));
file.write((char *) amp;fileheader, sizeof(BMFH));
file.write((char *) data, sizeof(unsigned char) * bytes);
Комментарии:
1. Спасибо за объяснение. Очень признателен. Эта большая диаграмма в Википедии была действительно полезной. Я могу начать понимать, как приложения могут обрабатывать растровое изображение … но поскольку оно в двоичном формате, как получается, что разработчики графических программ обрабатывают данные? Я так привык работать со строками, целыми числами, массивами, списками, картами и другими структурами данных, но все они содержат используемые данные, которыми можно легко манипулировать или читать как другие строки или целые числа. Я просто не вижу, как кто-то обрабатывает двоичные данные…
Ответ №2:
Прочитайте о двоичной сериализации в MSDN. Платформа .Net Framework в значительной степени помогает в этом.
Комментарии:
1. Спасибо! Это чрезвычайно полезно и похоже на то, что я искал. Я собираюсь обсуждать это в течение следующих нескольких часов 🙂 Еще раз большое спасибо!
2. Согласен, MSDN обладает обширными знаниями.
Ответ №3:
Да, многие приложения используют какие-то специфичные для приложения двоичные форматы, которыми нелегко манипулировать. Чтобы создать свой собственный двоичный формат, есть несколько вариантов:
- Техника двоичной сериализации
- Использование классов ввода-вывода для ручного чтения и записи байтов и фактическое создание файла произвольного доступа.
Комментарии:
1. Большое вам спасибо. Ссылка о создании файла произвольного доступа выглядит очень интересно…