Бинарный файл – это файл, в котором данные записаны в внутреннем представлении чисел, символов и структур (последовательности байтов), а не в виде человекочитаемых строк. Чтение и запись таких файлов предполагают интерпретацию байтов согласно заранее согласованной спецификации (формату): порядку байтов (endianness), длинам полей, кодировке строк, выравниванию и т. п.
Отличия от текстового файла:
Практическая ценность для ЕГЭ: умение интерпретировать и преобразовывать данные, понимать порядок байтов, рассчитывать смещения и размер элементов напрямую связано с задачами на обработку структур данных, числа в различных системах счисления, представления целых/вещественных типов и контроль корректности алгоритмов.
Байт, слово, поле, запись, заголовок
Байт – минимальная адресуемая единица хранения (8 бит).
Слово – машинная единица (обычно 16/32/64 бита).
Поле – логическая часть записи фиксированной или переменной длины.
Запись – последовательность полей (структура), повторяющаяся в файле.
Заголовок – префикс файла с метаданными: сигнатура (magic), версия, число записей, смещения, контрольные суммы.
Порядок байтов (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 формата. Если не определили – формат не переносим.
Выравнивание и паддинг (alignment)
Выравнивание – размещение полей по адресам, кратным их размеру (например, int32 по смещению, кратному 4). Это может порождать паддинг – «пустые» байты между полями.
Правило A1: при записи структур:
либо отключите неявный паддинг (упаковка, packed),
либо явно опишите паддинг в спецификации и соблюдайте его при чтении.
Фиксированные и переменные поля
Фиксированная длина упрощает позиционирование: смещение offset(i) записи i вычисляется как offset0 + i * record_size.
Переменная длина требует индексов/смещений (таблица offset’ов) или префиксных длин.
Правило L1: для переменных полей храните длину перед данными (prefix length) либо используйте таблицу смещений (индексная секция).
Потоковый и позиционный ввод-вывод
Потоковый I/O: чтение/запись последовательно, курсор (позиция) продвигается автоматически.
Позиционный I/O: явное управление позицией (seek, tell); доступ к произвольной записи по смещению.
Правило P1: для фиксированной структуры записей используйте позиционный доступ: он дает O(1) переход к i-й записи.
Буферизация
Буфер снижает число системных вызовов путем накопления данных. Важны режимы: без буфера, строчный, полный.
Правило B1: для крупных последовательных операций включайте полный буфер; для случайного доступа – контролируйте размер буфера и сброс (flush) после критических записей.
Память-отображённые файлы (mmap)
mmap даёт доступ к содержимому файла как к обычной памяти.
Правило M1: mmap эффективен для больших файлов и сканирования; но проверяйте границы и выравнивание, избегайте разыменования за пределами маппинга.
Знаковые целые и дополнительный код (two’s complement)
Для n-битного знакового:
Диапазон: [-2^(n-1) ; 2^(n-1) - 1].
Значение:
если старший бит s=0, то value = unsigned;
если s=1, то value = unsigned - 2^n.
Правило I1: при чтении знаковых целых выполняйте корректное знаковое расширение до размера типа исполнения.
Вещественные числа (IEEE 754)
Формат float32/float64 хранит знак, порядок, мантиссу. Прямое побайтовое копирование переносимо только при совпадающем endianness.
Правило F1: для межплатформенной переносимости вещественных предпочтительны целочисленное представление битов + явная перекладка по байтам (или стандартный формальный контейнер).
Строки в бинарных файлах
Подходы:
Fixed-length: фиксированная длина k, недостающие байты – нуль-паддинг; кодировка фиксирована (например, ASCII/UTF-8).
Length-prefixed: uint32 len затем len байтов строки.
Null-terminated: завершается 0x00 (C-style).
Правило S1: всегда указывайте кодировку и политику терминации/паддинга.
Общая структура файла (пример)
[ 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^32:
CRC = ( Σ byte[i] ) mod 2^32
или стандартный CRC32 (полиномиальная свёртка).
Правило C1: контрольная сумма/хеш обязательны для обнаружения повреждений.
Версионирование
VERSION фиксирует формат. При изменении полей – инкремент версии.
Правило V1: изменения формата должны быть расширяющими (backward-compatible) либо сопровождаться миграцией.

Запись фиксированной записи
Алгоритм:
Сформировать буфер записи согласно формату.
Уложить поля в нужном порядке и endianness.
Учесть паддинг (если требуется).
Записать блок write(buf, record_size).
Обновить индекс/счётчики/CRC.
Правило W1: одна логическая запись → одна атомарная операция записи, если возможно (минимум частичных состояний).
Чтение записи с позиционированием
Для фиксированного размера R и базы offset0:
offset(i) = offset0 + i * R
seek(offset(i))
read(R)
Далее – разбор полей, проверка инвариантов.
Правило R1: после чтения верифицируйте поля (диапазоны, длины, флаги).
Обновление записи in-place
Если размер постоянен, можно перезаписать участок. Для переменной длины используйте логическую замену: пометьте старую запись удалённой (флаг), добавьте новую в конец, перестройте индекс, при необходимости выполните компактирование.
Правило U1: обновления переменной длины – через «append-only + индекс» либо журналирование (WAL).
0 ≤ offset ≤ file_size
0 ≤ length ≤ file_size - offset
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.
Фиксированная структура записи
Формат 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.
Разбор:
читаем 32 байта;
распаковываем id, age, flags с учётом LE;
строку name обрезаем по нулю;
проверяем инварианты: age ≤ 130, flags в допустимом диапазоне.
Переменные строки с префиксной длиной
uint32 count
for k in [0..count-1]:
uint32 len
byte[len] payload (UTF-8)
Индексирование: храните массив смещений (или считывайте по цепочке, если последовательный доступ).
Обновление заголовка после записи
записать «сырой» блок данных;
посчитать CRC всего блока;
записать заголовок с COUNT, OFFSET_INDEX, CRC;
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) Оцените асимптотику доступа и компактирования.
Работа с бинарными файлами – это дисциплина строгой спецификации и точной реализации: каждый байт должен иметь однозначный смысл, каждое смещение – быть проверено, каждое число – интерпретировано в надлежащем порядке байтов и типе. Правильное проектирование формата (заголовок, индексы, контрольные суммы, версии), аккуратный позиционный ввод-вывод, контроль границ и переносимость делают системы устойчивыми и масштабируемыми.
Для ЕГЭ по информатике освоение темы укрепляет ключевые навыки: двоичное представление данных, вычисление смещений и размеров, проверка инвариантов, конструирование корректного алгоритма чтения/записи и оценка надёжности. Проработав изложенные правила и упражнения, вы сможете уверенно проектировать и обрабатывать бинарные форматы, аргументируя каждое решение с позиций корректности, производительности и переносимости.