Типизированный файл – это файл, в котором данные хранятся как последовательность элементов одного и того же статически определённого типа (например, целое, вещественное, «запись фиксированного формата»). В отличие от текстовых файлов, где данные представлены символами и требуют парсинга, типизированный файл позволяет обращаться к записям напрямую и интерпретировать их без дополнительного разбора. Такая модель лежит в основе двоичного ввода-вывода, ускоряет обработку больших массивов данных и формирует у ученика строгие представления о структуре данных – что напрямую помогает на ЕГЭ при решении задач на файловую обработку, сортировку, поиск, агрегирование и моделирование внешней памяти.
Логическая модель
Пусть T – статический тип. Типизированный файл представим как массив элементов типа T:
F = [ r0, r1, r2, ..., rN-1 ], где ri : T
Каждый элемент (запись) занимает фиксированный размер |T| (в байтах), если T – скаляр или упакованная запись фиксированного формата.
Адресация и смещения
Если используется заголовок файла размером H байт (может быть 0), то смещение записи с индексом i в байтах:
offset(i) = H + i * |T|
Где 0 ≤ i < N, N – текущее число записей. Чтение/запись по позиции i эквивалентны двоичному seek на offset(i) с последующим read/write длиной |T|.
Логические и физические записи
Логическая запись – элемент типа T на уровне языка.
Физическая запись (блок) – минимальная единица обмена с носителем (например, 4–64 КБ). Буферизацию между логическими и физическими уровнями выполняет среда/ОС.
Pascal: packed record … end;
C/C++: #pragma pack(push, 1) … #pragma pack(pop).
magic = «TYP1»
version = 1
record_size = |T|
endianness = 0 (LE) / 1 (BE)
count = N
Это обеспечит проверку целостности и упрощённое восстановление.

Объявление: var F: file of T;
Привязка имени: assign(F, 'data.bin');
Создание/перезапись: rewrite(F);
Открытие на чтение: reset(F);
Конец файла: eof(F)
Позиция/размер: filepos(F), filesize(F)
Перемещение: seek(F, i)
Чтение/запись элемента: read(F, x), write(F, x)
Закрытие: close(F)
S := 0
для i от 0 до N-1:
r := read(i)
если P(r) тогда S := S + f(r)
Сложность по времени O(N), по памяти O(1) (кроме буфера ввода-вывода).
Для больших файлов: формируем отсортированные серии в памяти и записываем их, затем многопутевым слиянием объединяем: классический external merge sort.
Строим вспомогательный массив пар (key, pos) в оперативной памяти, сортируем его по key, записываем как отдельный типизированный файл индекса. Поиск по ключу: бинарный поиск по индексу + seek(pos) в основном файле.
Безопасная операция «обновить запись i»:
seek(F, i) → read(F, r_old) (опционально),
подготовить r_new,
seek(F, i) → write(F, r_new).
Для атомарности сложных операций применяют «запись во временный файл + атомарный rename».
Правило 1 (буферизация). Читайте/пишите блоками; избегайте избыточных seek.
Правило 2 (фиксированная длина). Использование фиксированных записей упрощает адресацию и ускоряет доступ.
Правило 3 (локальность). Старайтесь проходить файл последовательно; случайный доступ группируйте.
Правило 4 (размер блока). Согласуйте размеры буферов с размером страницы/кластера ФС (типично 4–64 КБ).
Правило 5 (инварианты). Поддерживайте согласованность filesize(F) = N с собственными метаданными (если ведёте счётчик в заголовке).
Правило 6 (портируемость). Зафиксируйте упаковку записи, эндианность и кодировку; документируйте формат.
На ЕГЭ встречаются задачи, где требуется:
Типизированные файлы дисциплинируют мышление: данные строго типизированы, известен размер записи, легко формализуются инварианты и «адресная» арифметика – всё это снижает количество ошибок и помогает получать правильные ответы.
Смещение записи:
offset(i) = H + i * |T|
Диапазон допустимых индексов:
0 ≤ i < N и N = filesize(F)
Линейное агрегирование:
T(N) = Θ(N), память = O(1)
Безопасное обновление записи i:
seek(F, i); write(F, r_new)
type TIntFile = file of Integer;
var F: TIntFile; x: Integer; i: Integer;
assign(F, 'nums.bin');
rewrite(F);
for i := 1 to n do begin
readln(x); // из консоли/текста
write(F, x); // двоично в типизированный файл
end;
close(F);
var F: TIntFile; cnt, val: Integer;
assign(F, 'nums.bin'); reset(F);
cnt := 0;
while not eof(F) do begin
read(F, val);
if val mod 2 = 0 then cnt := cnt + 1;
end;
close(F);
writeln('Чётных: ', cnt);
var F: TIntFile; i, val: Integer;
assign(F, 'nums.bin'); reset(F);
if (i >= 0) and (i < filesize(F)) then begin
seek(F, i);
read(F, val);
writeln('F[i] = ', val);
end;
close(F);
type
TStudent = packed record
id: LongInt;
group: Word;
avg: Single; // IEEE-754
name: array[0..31] of AnsiChar; // 32 байта, нулевой терминатор
end;
var S: file of TStudent; st: TStudent;
Упражнение 1. Адресная арифметика и корректность индексов
В двоичном файле хранятся N записей фиксированной длины |T| = 20 байт. Заголовка нет (H = 0).
a) Запишите формулу смещения offset(i).
b) Докажите, что доступ по индексу i корректен тогда и только тогда, когда 0 ≤ i < N.
c) Найдите смещение последней записи (с индексом N-1) и объясните, почему выход за пределы приводит к ошибке чтения.
Упражнение 2. Проектирование записи и переносимость
Нужно хранить сотрудников: (id:Int32, dept:UInt16, salary:Float32, name: фикс. 24 байта в UTF-8 без многобайтовых символов).
a) Укажите точный размер записи в байтах при упаковке и без неё (кратко обоснуйте появление паддинга).
b) Предложите сигнатуру заголовка с полями magic, version, endianness, record_size, count.
c) Опишите процедуру чтения на другой платформе с иной эндианностью: какие поля нужно конвертировать?
Упражнение 3. Индекс "ключ → позиция"
Имеется основной файл записей TStudent и вспомогательный индекс-файл, содержащий пары (id, pos), отсортированные по id.
a) Опишите алгоритм поиска студента по id (бинарный поиск по индексу + прямой доступ).
b) Оцените временную сложность в терминах N (число записей) и B (размер блока чтения).
c) Предложите стратегию обновления индекса при добавлении новой записи в конец основного файла.
Упражнение 4. Однопроходная агрегация
В типизированном файле целых лежит последовательность температур (целые). Требуется найти: среднее по всем, число значений выше среднего, минимум/максимум.
a) Предложите алгоритм за один проход без хранения всех значений (подсказка: одновременно вести сумму, счётчик, min, max).
b) Оцените погрешность среднего при больших N с 32-битной суммой (когда целесообразно переходить на 64-бит).
c) Обоснуйте сложность и требование к памяти.
Упражнение 5. Внешняя сортировка
Файл целых не помещается в память (RAM недостаточно).
a) Опишите этапы внешней сортировки: формирование серий в памяти размером M элементов, запись серий, k-путевое слияние.
b) Оцените число проходов по файлу при заданных N и M (используйте порядок величин: ≈ ⌈log_k (N/M)⌉ + 1).
c) Предложите схему именования временных файлов и правила их безопасного удаления при нештатном завершении.
Типизированные файлы – строго определённая и высокоэффективная форма хранения, позволяющая работать с данными как с массивом записей фиксированного типа. Чёткая адресная арифметика, возможность прямого доступа и предсказуемая сложность делают их идеальной почвой для отработки алгоритмов внешней памяти, индексации и безопасных обновлений. В контексте ЕГЭ это означает: уверенное владение файловыми примитивами, умение оценивать ресурсы, поддерживать инварианты и проектировать корректные структуры – навыки, которые непосредственно повышают качество и скорость решения экзаменационных задач.