БЕСПЛАТНАЯ ПОДГОТОВКА К ЕГЭ ПО ПРОФИЛЬНОЙ МАТЕМАТИКЕ
Подготовься к ЕГЭ-2026 по профильной математике самостоятельно с помощью сервиса "1С:Репетитор"!
Понятная теория и эффективные тренажеры с объяснением! Вы успеете подготовиться к экзамену! Начните занятия прямо сейчас!
design_arrow
Работа с бинарными файлами

Работа с бинарными файлами

Бинарный файл – это файл, в котором данные записаны в внутреннем представлении чисел, символов и структур (последовательности байтов), а не в виде человекочитаемых строк. Чтение и запись таких файлов предполагают интерпретацию байтов согласно заранее согласованной спецификации (формату): порядку байтов (endianness), длинам полей, кодировке строк, выравниванию и т. п.

Отличия от текстового файла:

  • Текст хранит символы в кодировке (например, UTF-8), а бинарный – значения в их машинной форме (например, int32, float64 и т. д.).
  • В тексте разделители (пробел, табуляция, перевод строки) имеют смысл, а в бинарном смысл задаёт описание полей.
  • Бинарные файлы компактнее и быстрее обрабатываются, но требуют строгого соблюдения формата при чтении/записи.

Практическая ценность для ЕГЭ: умение интерпретировать и преобразовывать данные, понимать порядок байтов, рассчитывать смещения и размер элементов напрямую связано с задачами на обработку структур данных, числа в различных системах счисления, представления целых/вещественных типов и контроль корректности алгоритмов.

Формальная модель и базовые понятия

  1. Байт, слово, поле, запись, заголовок

    • Байт – минимальная адресуемая единица хранения (8 бит).

    • Слово – машинная единица (обычно 16/32/64 бита).

    • Поле – логическая часть записи фиксированной или переменной длины.

    • Запись – последовательность полей (структура), повторяющаяся в файле.

    • Заголовок – префикс файла с метаданными: сигнатура (magic), версия, число записей, смещения, контрольные суммы.

  2. Порядок байтов (endianness)

    • Little-endian: младший байт младшего разряда идёт первым.

    • Big-endian: старший байт идёт первым.

    Пусть 32-битное целое x имеет байты b0 b1 b2 b3. Тогда:

    • Little-endian: x = b0 + 256*b1 + 256^2*b2 + 256^3*b3.

    • Big-endian: x = b3 + 256*b2 + 256^2*b1 + 256^3*b0.

    Правило E1: всегда фиксируйте endianness формата. Если не определили – формат не переносим.

  3. Выравнивание и паддинг (alignment)

    Выравнивание – размещение полей по адресам, кратным их размеру (например, int32 по смещению, кратному 4). Это может порождать паддинг – «пустые» байты между полями.

    Правило A1: при записи структур:

    • либо отключите неявный паддинг (упаковка, packed),

    • либо явно опишите паддинг в спецификации и соблюдайте его при чтении.

  4. Фиксированные и переменные поля

    • Фиксированная длина упрощает позиционирование: смещение offset(i) записи i вычисляется как offset0 + i * record_size.

    • Переменная длина требует индексов/смещений (таблица offset’ов) или префиксных длин.

    Правило L1: для переменных полей храните длину перед данными (prefix length) либо используйте таблицу смещений (индексная секция).

Модель ввода-вывода: позиционный доступ, буферизация, mmap

  1. Потоковый и позиционный ввод-вывод

    • Потоковый I/O: чтение/запись последовательно, курсор (позиция) продвигается автоматически.

    • Позиционный I/O: явное управление позицией (seek, tell); доступ к произвольной записи по смещению.

    Правило P1: для фиксированной структуры записей используйте позиционный доступ: он дает O(1) переход к i-й записи.

  2. Буферизация

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

    Правило B1: для крупных последовательных операций включайте полный буфер; для случайного доступа – контролируйте размер буфера и сброс (flush) после критических записей.

  3. Память-отображённые файлы (mmap)

    mmap даёт доступ к содержимому файла как к обычной памяти.

    Правило M1: mmap эффективен для больших файлов и сканирования; но проверяйте границы и выравнивание, избегайте разыменования за пределами маппинга.

Представление чисел и строк: целые, вещественные, кодировки

  1. Знаковые целые и дополнительный код (two’s complement)

    Для n-битного знакового:

    • Диапазон: [-2^(n-1) ; 2^(n-1) - 1].

    • Значение:
      если старший бит s=0, то value = unsigned;
      если s=1, то value = unsigned - 2^n.

    Правило I1: при чтении знаковых целых выполняйте корректное знаковое расширение до размера типа исполнения.

  2. Вещественные числа (IEEE 754)

    Формат float32/float64 хранит знак, порядок, мантиссу. Прямое побайтовое копирование переносимо только при совпадающем endianness.

    Правило F1: для межплатформенной переносимости вещественных предпочтительны целочисленное представление битов + явная перекладка по байтам (или стандартный формальный контейнер).

  3. Строки в бинарных файлах

    Подходы:

    • Fixed-length: фиксированная длина k, недостающие байты – нуль-паддинг; кодировка фиксирована (например, ASCII/UTF-8).

    • Length-prefixed: uint32 len затем len байтов строки.

    • Null-terminated: завершается 0x00 (C-style).

    Правило S1: всегда указывайте кодировку и политику терминации/паддинга.

Спецификация формата: минимально необходимый контракт

  1. Общая структура файла (пример)

    [ MAGIC(4) | VERSION(2) | FLAGS(2) | COUNT(4) | OFFSET_INDEX(8) | RESERVED(8) ]

    [ DATA SECTION ... ]

    [ INDEX SECTION: COUNT записей по 8 байт (смещение каждой записи) ]

    [ FOOTER: CRC32(4) | END(4) ]

  2. Контрольная сумма

    Пример простой суммы по модулю 2^32:

    CRC = ( Σ byte[i] ) mod 2^32

    или стандартный CRC32 (полиномиальная свёртка).

    Правило C1: контрольная сумма/хеш обязательны для обнаружения повреждений.

  3. Версионирование

    VERSION фиксирует формат. При изменении полей – инкремент версии.

    Правило V1: изменения формата должны быть расширяющими (backward-compatible) либо сопровождаться миграцией.

Информатика–схема открытия и закрытия бинарных файлов

Операции над бинарными файлами: чтение, запись, обновление

  1. Запись фиксированной записи

    Алгоритм:

    1. Сформировать буфер записи согласно формату.

    2. Уложить поля в нужном порядке и endianness.

    3. Учесть паддинг (если требуется).

    4. Записать блок write(buf, record_size).

    5. Обновить индекс/счётчики/CRC.

    Правило W1: одна логическая запись → одна атомарная операция записи, если возможно (минимум частичных состояний).

  2. Чтение записи с позиционированием

    Для фиксированного размера R и базы offset0:

    offset(i) = offset0 + i * R

    seek(offset(i))

    read(R)

    Далее – разбор полей, проверка инвариантов.

    Правило R1: после чтения верифицируйте поля (диапазоны, длины, флаги).

  3. Обновление записи in-place

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

    Правило U1: обновления переменной длины – через «append-only + индекс» либо журналирование (WAL).

Переносимость, совместимость, безопасность

  • Endianness: нормализуйте к сетевому порядку (big-endian) или фиксируйте один порядок; при чтении выполняйте перекладку.
  • Выравнивание: избегайте зависимостей от ABI компилятора (используйте упакованные структуры или явную запись полей).
  • Переполнение/утечки: проверяйте длины перед выделением буферов; не доверяйте данным из файла.
  • Атомарность/целостность: обновляйте заголовок в конце транзакции; используйте временный файл + rename() для атомарной замены.
Правило S2 (безопасность): любая длина/смещение из файла – подозрительны, проверяйте:

0 ≤ offset ≤ file_size

0 ≤ length ≤ file_size - offset

Типичные ошибки и анти-паттерны

  1. Чтение «как есть» структур языка с неявным паддингом – несоответствие формату.
  2. Игнорирование endianness – «перевёрнутые» числа.
  3. Отсутствие проверки границ – переполнение буфера.
  4. Отсутствие контроля целостности – тихая порча данных.
  5. Отсутствие версионирования – невозможность эволюции формата.

Мини-шпаргалка 

E1  Фиксируйте endianness и указывайте его в заголовке.

A1  Паддинг описывайте явно или отключайте упаковкой.

L1  Переменные поля: prefix length или индекс смещений.

P1  Фиксированные записи → позиционный доступ O(1).

B1  Для больших записей используйте буферизацию и flush.

M1  mmap → проверка границ и выравнивания.

I1  Корректное знаковое расширение целых.

F1  Переносимость вещественных: через битовое представление.

S1  Строки: кодировка + терминатор/длина обязательны.

C1  Контрольная сумма в заголовке/футере.

V1  Версионирование формата и миграции.

W1  Атомарная запись логической записи.

R1  Верификация полей после чтения.

U1  Переменная длина → append-only + индекс.

S2  Всегда проверяйте offset/length против file_size.

Связь с ЕГЭ по информатике

  • Представление данных: двоичное кодирование чисел и строк, работа с разрядами и масками.
  • Алгоритмы и структуры: индексные таблицы, поиск по смещениям, обработка последовательностей.
  • Моделирование памяти: расчёт смещений, выравнивание, оценка объёма данных.
  • Надёжность: контрольные суммы и верификация – аналог задач на проверку корректности.
  • Практика программирования: строго заданный формат ввода-вывода, аккуратная работа с границами и типами. 

Практические примеры (язык-нейтральные идеи с иллюстрациями)

  1. Фиксированная структура записи

    Формат Person (фиксированная длина 32 байта):

    uint32  id          (4 байта, LE)

    uint16  age         (2 байта, LE)

    uint16  flags       (2 байта, LE)

    char    name[24]    (24 байта, ASCII, null-padded)

    Размер R = 32. Смещение записи i: base + 32*i.

    Разбор:

    1. читаем 32 байта;

    2. распаковываем id, age, flags с учётом LE;

    3. строку name обрезаем по нулю;

    4. проверяем инварианты: age ≤ 130, flags в допустимом диапазоне.

  2. Переменные строки с префиксной длиной

    uint32 count

    for k in [0..count-1]:

        uint32 len

        byte[len] payload (UTF-8)

    Индексирование: храните массив смещений (или считывайте по цепочке, если последовательный доступ).

  3. Обновление заголовка после записи

    1. записать «сырой» блок данных;

    2. посчитать CRC всего блока;

    3. записать заголовок с COUNT, OFFSET_INDEX, CRC;

    4. flush + fsync (где доступно) → целостность.

Пять упражнений 

Упражнение 1. Расчёт смещений и размеров

Формат: запись длиной R=24 байта:
uint32 id; uint16 year; uint16 month; uint64 salary; uint32 crc; (LE, без паддинга).
a) Укажите смещение каждого поля в байтах.
b) Для файла размером N байт найдите число полных записей K = ⌊N / 24⌋.
c) Выведите формулу offset(i) для i-й записи, если база base=128.

Упражнение 2. Endianness и интерпретация

Дано 4 байта: 3A 01 00 00.
a) Каково значение uint32 в LE и в BE?
b) Если это int32 в LE, чему равно значение? (Подсказка: старший бит 0 → неотрицательное).
c) Запишите общую формулу приведения из LE к целому.

Упражнение 3. Строки и кодировки

В записи хранится: uint16 len; byte[len] s (UTF-8).
a) Какие проверки на корректность длины следует выполнить при чтении?
b) Предложите правило обрезки нуль-терминатора, если он присутствует внутри s.
c) Обоснуйте, почему длина в байтах не равна числу символов при UTF-8.

Упражнение 4. Контрольная сумма

Для блока data длиной L определена контрольная сумма: CRC = ( Σ_{i=0..L-1} data[i] ) mod 2^32

a) Выполните расчёт CRC для последовательности байтов 01 02 03 FF.
b) Объясните, как обнаружить одно-битовую ошибку.
c) Почему такая сумма хуже, чем полиномиальный CRC32, и когда её всё же достаточно?

Упражнение 5. Индексы и переменная длина

Формат: заголовок с COUNT, затем индекс из COUNT записей по 8 байт (смещения), далее сами записи переменной длины.
a) Как найти k-ю запись?
b) Предложите алгоритм компактирования после удаления нескольких записей.
c) Оцените асимптотику доступа и компактирования.

Развёрнутые правила проектирования форматов (чек-лист)

  1. Однозначность: каждое поле имеет тип, размер, endianness, допустимые диапазоны.
  2. Самоописание: заголовок содержит сигнатуру, версию, размеры секций.
  3. Локализация ошибок: контрольные суммы по секциям, а не только по всему файлу.
  4. Эволюция: версии, совместимость, возможно – таблица опций (TLV: Type-Length-Value).
  5. Безопасность: проверка всех длин/смещений, запрет отрицательных смещений, защита от integer overflow при вычислениях offset + length.
  6. Производительность: фиксированные записи там, где это возможно; индексы для переменных данных; батч-запись.
  7. Тестируемость: эталонные «золотые» файлы, валидатор формата, fuzz-тестирование.

Заключение

Работа с бинарными файлами – это дисциплина строгой спецификации и точной реализации: каждый байт должен иметь однозначный смысл, каждое смещение – быть проверено, каждое число – интерпретировано в надлежащем порядке байтов и типе. Правильное проектирование формата (заголовок, индексы, контрольные суммы, версии), аккуратный позиционный ввод-вывод, контроль границ и переносимость делают системы устойчивыми и масштабируемыми.

Для ЕГЭ по информатике освоение темы укрепляет ключевые навыки: двоичное представление данных, вычисление смещений и размеров, проверка инвариантов, конструирование корректного алгоритма чтения/записи и оценка надёжности. Проработав изложенные правила и упражнения, вы сможете уверенно проектировать и обрабатывать бинарные форматы, аргументируя каждое решение с позиций корректности, производительности и переносимости.