Записи, помеченные на удаление: главный источник расхождений
В DBF удаление не удаляет. Запись остаётся на месте, меняется один байт — и дальше всё зависит от того, обращает ли на него внимание программа, которая файл читает.
Как это устроено
Каждая запись в DBF начинается со служебного байта. Пробел (0x20) означает «запись активна», звёздочка (0x2A) — «помечена на удаление». Всё остальное содержимое записи сохраняется как было.
Физически данные исчезают только после операции PACK: она переписывает файл, оставляя лишь активные записи. До этого момента удалённая запись — полноценная строка, которую можно прочитать, а в некоторых программах и восстановить.
Почему из-за этого расходятся отчёты
Типичная ситуация: одна программа показывает 1 638 записей, другая — 1 815, третья выгружает в Excel 1 815 строк, а бухгалтер считает по 1 638. Все три правы — просто по-разному настроены.
В dBase и FoxPro поведение зависит от настройки SET DELETED ON/OFF. В драйверах ODBC — от параметра соединения. В самодельных выгрузках — от того, вспомнил ли разработчик про этот байт. Универсальные конвертеры в CSV чаще всего про него не помнят и выгружают всё подряд.
Поэтому первое, что стоит сделать при расхождении, — посмотреть, сколько в файле помеченных на удаление записей. Часто разница ровно на это число.
Что с ними делать
- Скрыть — поведение по умолчанию и то, чего ожидает большинство. Так вы видите таблицу такой, какой её видит рабочая программа.
- Показать вместе со всеми — когда нужно понять полный объём файла или найти «потерянные» данные.
- Оставить только их — самый интересный режим. Видно, что именно удалили: иногда это ошибочно снятые записи, иногда следы неудачной загрузки.
Помеченные записи можно отфильтровать и выгрузить отдельным файлом — например, чтобы передать тому, кто разбирается в причинах.
Осторожно с упаковкой
Запуск PACK необратим: после него данные не восстановить ничем, кроме резервной копии. Кроме того, упаковка меняет физические номера записей — и все внешние ссылки на них (в том числе в индексах и в чужих таблицах) становятся неверными.
По этой же причине TablesViewer при сохранении правок не упаковывает файл: изменённые записи переписываются на своих местах, остальные байты копируются как есть. Номера записей сохраняются.
Частые вопросы
Как восстановить помеченную на удаление запись?
Снять флаг: заменить звёздочку на пробел в служебном байте. В TablesViewer это делается через контекстное меню строки в режиме правки.
Влияют ли удалённые записи на размер файла?
Да, они занимают место до упаковки. Файл с большим числом помеченных записей может быть вдвое больше полезных данных.
Почему индекс показывает записи, которых нет?
Индексы .cdx и .ntx обновляются отдельно. Если файл правили в обход индекса, он мог устареть — его нужно перестроить.