Работа с внешними файлами формата DBF через объект XBase в платформе 1С — это классический способ интеграции с унаследованными системами или обмена данными. Однако этот механизм таит в себе множество подводных камней, связанных с особенностями движка FoxPro, который лежит в основе обработки этих файлов. Одной из самых загадочных ошибок является Error #: -20 Creating File Temporary Working File. На первый взгляд она кажется системной, связанной с правами доступа или отсутствием места на диске, но зачастую причина кроется в самой структуре кода или данных. Рассмотрим подробно, как диагностировать и устранить эту проблему.
Представим типичный сценарий: у нас есть база данных (таблица соответствия), содержащая сотни тысяч записей (например, более 200 000). Для ускорения поиска мы программно создаем индексный файл (CDX). В процессе переиндексации или при попытке сжатия файла встроенными методами 1С внезапно прерывает работу с сообщением об ошибке создания временного файла. Проанализируем типичный код инициализации такой базы:
БД_ТС = Новый XBase;
ФайлБД_ТС = Новый Файл(ФайлТС);
ФайлИндексовБД_ТС = Новый Файл(ИмяФайлаИндексовТС);
Если ФайлБД_ТС.Существует() Тогда
Если НЕ БД_ТС.Открыта() Тогда
БД_ТС.индексы.Добавить("IndSource", "TRIM(ID_Source)", Истина);
Если ФайлИндексовБД_ТС.Существует() Тогда
БД_ТС.ОткрытьФайл(ФайлТС, ИмяФайлаИндексовТС, Ложь);
Иначе
БД_ТС.ОткрытьФайл(ФайлТС,, Ложь);
Если НЕ БД_ТС.СоздатьИндексныйФайл(ИмяФайлаИндексовТС) Тогда
Сообщить("Ошибка создания индекса!");
КонецЕсли;
КонецЕсли;
КонецЕсли;
Иначе
// Создание структуры нового файла
БД_ТС.поля.Добавить("ID_Source", "S", 50);
БД_ТС.поля.Добавить("ID_Receive", "S", 50);
БД_ТС.индексы.Добавить("IndSource", "TRIM(ID_Source)", Истина);
БД_ТС.СоздатьФайл(ФайлТС, ИмяФайлаИндексовТС);
КонецЕсли;
Ошибка часто возникает на этапе вызова метода БД_ТС.Переиндексировать() или БД_ТС.Сжать(). Особенность в том, что сам DBF-файл может быть исправен и открываться сторонними редакторами, но 1С не может завершить технологическую операцию.
Выясним причину, связанную с методом Сжать(). Этот метод предназначен для физического удаления записей, помеченных на удаление (аналог команды PACK в FoxPro). Процесс работы метода Сжать() выглядит так: 1С создает временную копию файла, переносит туда только «живые» записи, перестраивает индексы и заменяет оригинал. Если в этот момент индексный файл уже открыт или имеет логические ошибки в структуре выражений, возникает конфликт дескрипторов файлов. Разберем, почему отказ от Сжать() часто решает проблему: при больших объемах данных (сотни мегабайт) и активном использовании индексов, операции записи во временные файлы могут блокироваться антивирусом или самой операционной системой из-за слишком частых обращений. Если ваша задача — просто актуализировать индексы, достаточно использовать Переиндексировать(), предварительно удалив старый CDX-файл программно.
Это одна из самых критических ошибок проектирования DBF. Рассмотрим подробнее, как работает индексация в формате XBase. Индексный ключ должен иметь фиксированную длину для каждой записи в файле. Когда мы пишем TRIM(ID_Source), мы фактически просим движок базы данных вычислять длину ключа «на лету».
Проанализируем риски использования TRIM() в индексах:
TRIM в индексах, дополняя результат пробелами до максимальной длины поля, но реализация XBase в 1С 8.х может вести себя иначе в зависимости от версии платформы.Правильное решение: Всегда используйте чистое имя поля без функций обрезки пробелов. Движок сам корректно обработает значения, дополненные пробелами справа. Исправим код создания индекса:
// Вместо: БД_ТС.индексы.Добавить("IndSource", "TRIM(ID_Source)", Истина);
// Используем:
БД_ТС.индексы.Добавить("IndSource", "ID_Source", Истина);
Если при добавлении индекса установлен третий параметр Истина (Уникальность), 1С ожидает, что в файле нет дублирующихся значений по этому полю. Если файл DBF формировался внешним источником или ранее в него записывались данные без контроля уникальности, то при вызове Переиндексировать() возникнет ошибка. Проблема в том, что диагностика объекта XBase довольно скудная, и вместо понятного сообщения «Дубликат ключа», система выдает общую ошибку ввода-вывода (Error -20).
Для исправления ситуации выполним следующие шаги:
ID_Source.Ложь.Текст ошибки прямо указывает на «Temporary Working File». Это означает, что 1С не смогла создать временный файл в системной директории. Проанализируем возможные внешние факторы:
%TEMP%.C:\DB\base.dbf) и повторить операцию.XBase могут давать сбой).Чтобы избежать ошибки -20 и гарантировать стабильную работу с большими DBF-файлами, рекомендуем придерживаться следующего алгоритма действий:
.cdx с диска, используя УдалитьФайлы(). Это очистит «мусор» и исключит конфликты со старой структурой.TRIM, ALLTRIM или сложные вычисления в строке индекса. Только прямые имена полей в верхнем регистре.Сжать(). Если это необходимо — делайте это отдельным этапом до подключения индексов.Рассмотрим пример надежного кода для пересоздания индексов:
ПутьКФайлу = "C:\Data\ts.dbf";
ПутьКИндексу = "C:\Data\ts.cdx";
БД = Новый XBase;
// 1. Сначала удаляем старый индексный файл через системные средства
ФайлИнд = Новый Файл(ПутьКИндексу);
Если ФайлИнд.Существует() Тогда
Попытка
УдалитьФайлы(ПутьКИндексу);
Исключение
Сообщить("Файл индекса занят другим процессом!");
Возврат;
КонецПопытки;
КонецЕсли;
// 2. Открываем только DBF
БД.ОткрытьФайл(ПутьКФайлу);
// 3. Добавляем индексы БЕЗ TRIM
БД.Индексы.Добавить("ID_IDX", "ID_SOURCE", Ложь); // Ложь - если не уверены в уникальности
// 4. Создаем новый файл
Если БД.СоздатьИндексныйФайл(ПутьКИндексу) Тогда
Сообщить("Индексация завершена успешно");
Иначе
Сообщить("Ошибка при создании индекса");
КонецЕсли;
БД.ЗакрытьФайл();
Соблюдение этих правил позволит вам избежать большинства низкоуровневых ошибок при работе с XBase и обеспечит высокую скорость обработки данных даже в очень больших таблицах.