Как читать куски (неизвестного размера) двоичного файла?

0

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

struct student{
int Roll_No;
char Name[10];
}

Затем после обновления переменных с содержимым и сохранения в двоичном файле двоичный файл имеет 14 байтов, 10 байтов символов и 4 из int, поэтому, если мы проанализируем файл в шестнадцатеричном файле, файл имеет 4 байта, зарезервированных для Roll_no и 10 байтов зарезервированы для имени, в котором заполненное содержимое заполнено, а другие могут рассматриваться как точки в файле, я имею в виду, если мы создадим программу со структурой/классом, как указано выше, и после сохранения содержимого в файл размер файла так же, как мы создали структуру, я имею в виду 4 из int и 10 символов, поэтому, насколько мне известно, я создал новый формат изображения, например. (Dot).MyIMG, из моей программы, которая представляет собой класс/класс

struct MyIMG{
char Header[5];
int width, height;
int Pixels[124000];
}

Затем моя программа создаст новый файл размером 49613 байт или 49 килобайт (что составляет 5 заголовков, + (плюс) 8 от высоты и ширины int, + (плюс) 4 × 124000 от пикселов int), тем более, что пиксели равны 4, 8, 100 или все, что он напишет весь массив пикселей, пуст, так почему этот эффект не может быть таким же на любом большом программном обеспечении, таком как MSpaint, Adobe photoshop, что они делают, что заставляет их записывать файлы, размер которых зависит от пиксели хранятся в сети, а не пустые массивы...

EDIT: Я теперь отредактировал свой вопрос и четко определил свой вопрос, помогите мне, спасибо заранее!

  • 1
    Точки не означают «ничего», они означают «непечатный символ».
  • 5
    Это ... это все одно предложение?
Показать ещё 4 комментария
Теги:

2 ответа

2

Форматы файлов, такие как.png и.bmp, имеют определенный формат. Форматы файлов могут указывать макет байтов (например, 4 байта для ширины, 4 байта для высоты, 2 МБ данных пикселя RGBA или что-то еще), или формат может предоставить вам информацию о размере различных объектов.

Например, в файле TIFF указывается, что в этом файле есть числовые теги при определенных смещениях байта. Затем эти теги содержат информацию о размере, местоположении и формате данных изображения. Таким образом, у вас может быть заголовок фиксированного размера, в котором говорится: "Список тегов начинается с байта 100 и содержит 40 тегов". Каждый тег будет фиксированным размером (скажем, 16 байт), поэтому вы знаете, что читаете 40 16-байтовых блоков, начиная с байта 100. Затем теги будут содержать информацию, такую как смещение байта начала данных изображения, сколько байтов в пикселе и сколько пикселей есть. Из этого вы можете прочитать данные, не зная заранее, что такое весь формат.

1

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

size_t name_len = strlen(my_student.Name);
my_ofstream.write((const char*)&my_student, sizeof my_student - sizeof my_student.Name + name_len + 1);

Затем это имя записывается в двоичный файл и включается первый символ 0/NUL. Когда вы читаете файл обратно, программа может читать блок данных из ifstream тогда - зная, что student хранится с некоторым смещением, используйте strlen() в .Name части входящих данных для восстановления длины, отчасти потому, что может копировать только необходимые данные объекту- student, а также знать, с чего начать разбор следующего элемента данных из входного потока:

char buffer[32768];
student my_student;
if (my_ifstream.read(buffer, sizeof buffer) && my_ifstream.gcount() > 5)
{
    // check for NUL without risking reading buffer[.gcount()]
    size_t pre_name_len = std::offsetof(student, name);
    const char* p_name = buffer + pre_name_len;
    const char* p_nul = strnchr(p_name,
                                std::min(10, my_ifstream.gcount() - pre_name_len),
                                '\0');
    if (p_nul == nullptr || *p_nul != '\0')
        throw std::runtime_error("file didn't contain complete student record");
    memcpy(my_student, buffer, p_nul - buffer + 1);

    // keep parsing input from p_nul + 1, not going past .gcount()
}

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню