При интеграции 1С с внешними или унаследованными информационными системами часто возникает задача формирования и передачи данных в формате dBase (файлы с расширением .dbf). На практике разработчики нередко сталкиваются с ошибками при выгрузке таблицы значений в DBF: от неверного обхода строк коллекции до проблем с кодировкой и передачей ссылочных данных. Рассмотрим подробно, как правильно организовать выгрузку данных из системы компоновки данных (СКД) и таблицы значений в файл DBF с помощью встроенного объекта XBase.
Проанализируем типовую ситуацию: результат СКД был успешно выгружен в объект ТаблицаЗначений, после чего предпринимается попытка наполнить DBF-файл. Частая ошибка начинающих разработчиков — обращение к коллекции колонок вместо обращения к конкретным строкам в цикле:
// Ошибочный подход:
Для N = 1 По ТЗ.Количество() Цикл
БД.UrLizo = ТЗ.Колонки.Получить(1); // Ошибка: обращение к объекту "КолонкаТаблицыЗначений", а не к данным строки
КонецЦикла;
Метод ТЗ.Колонки.Получить() возвращает описание колонки, а не значение в текущей строке. Для корректного заполнения файла базы данных необходимо обходить именно строки таблицы значений.
Разберем процесс создания и наполнения DBF-файла по шагам:
Кодировка следует задавать до создания или открытия файла. В 1С поддерживаются два формата: КодировкаXBase.ANSI (Windows-1251) и КодировкаXBase.OEM (DOS / CP866).БД.Поля.Добавить(). Важно помнить об ограничениях формата dBase: имя поля не должно быть длиннее 10 символов и должно содержать только латиницу, цифры и знаки подчеркивания.БД.СоздатьФайл() физически формирует файл с заданной структурой.БД.Добавить(), заполняем поля и фиксируем запись методом БД.Записать().БД.ЗакрытьФайл(), чтобы освободить дескриптор в операционной системе. Рекомендуется использовать конструкцию Попытка ... Исключение, чтобы файл гарантированно закрывался даже в случае возникновения ошибки при записи.Посмотрим на практический пример реализации:
Процедура ВыгрузитьТЗвDBF(ТЗ, ПутьКФайлу)
БД = Новый XBase;
// Указываем кодировку (ANSI для Windows или OEM для DOS)
БД.Кодировка = КодировкаXBase.ANSI;
// Добавляем поля в структуру (имя поля <= 10 символов)
БД.Поля.Добавить("URLIZO", "S", 100);
БД.Поля.Добавить("KONTRAGENT", "S", 100);
БД.Поля.Добавить("SCHET", "S", 10);
БД.Поля.Добавить("OSTATOKDT", "N", 15, 2);
БД.Поля.Добавить("OSTATOKKT", "N", 15, 2);
Попытка
БД.СоздатьФайл(ПутьКФайлу);
// Правильный обход строк таблицы значений
Для Каждого СтрокаТЗ Из ТЗ Цикл
// Проверяем заполненность ключевых полей при необходимости
Если ЗначениеЗаполнено(СтрокаТЗ.Организация) И ЗначениеЗаполнено(СтрокаТЗ.Контрагент) Тогда
БД.Добавить();
// Присваиваем строковые и числовые значения
БД.URLIZO = Строка(СтрокаТЗ.Организация);
БД.KONTRAGENT = Строка(СтрокаТЗ.Контрагент);
БД.SCHET = Строка(СтрокаТЗ.Счет);
БД.OSTATOKDT = СтрокаТЗ.ОстатокДт;
БД.OSTATOKKT = СтрокаТЗ.ОстатокКт;
БД.Записать();
КонецЕсли;
КонецЦикла;
Исключение
Сообщить("Ошибка при выгрузке в DBF: " + ОписаниеОшибки());
КонецПопытки;
// Закрываем файл, если он открыт
Если БД.Открыта() Тогда
БД.ЗакрытьФайл();
КонецЕсли;
КонецПроцедуры
Объект XBase не работает со ссылочными типами 1С (такими как СправочникСсылка или ДокументСсылка), а также со значениями Null и Неопределено. Все ссылочные значения необходимо явно преобразовывать в строки или извлекать конкретные реквизиты.
Если в DBF-файл требуется выгрузить, например, ИНН контрагента или организации, можно обратиться к реквизиту напрямую: СтрокаТЗ.Контрагент.ИНН. Однако обращение через точку в цикле приводит к дополнительным неявным запросам к базе данных на каждой итерации. Чтобы оптимизировать быстродействие, добавьте поле Контрагент.ИНН непосредственно в набор данных СКД и выведите его отдельной колонкой в результирующую таблицу значений.
Рассмотрим универсальный алгоритм, который автоматически создает DBF-файл на основе колонок переданной таблицы значений с динамическим сопоставлением типов 1С и dBase:
Функция СоздатьНовыйФайлDBF(тз, ПолныйПутьКФайлуDBF, XB = Неопределено)
Если НЕ XB = Неопределено Тогда
Возврат XB;
КонецЕсли;
Файл = Новый XBase;
Файл.Кодировка = КодировкаXBase.ANSI;
Для Каждого Колонка Из тз.Колонки Цикл
КолонкаТиповая = Ложь;
Попытка
Если Найти(Строка(Колонка.ТипЗначения), "Строка") > 0 Тогда
Длина = Колонка.ТипЗначения.КвалификаторыСтроки.Длина;
// В DBF максимальная длина строкового поля типа "S" составляет 254 символа
ДлинаПоля = ?(Длина > 0 И Длина <= 254, Длина, 254);
Файл.Поля.Добавить(Лев(Колонка.Имя, 10), "S", ДлинаПоля);
КолонкаТиповая = Истина;
ИначеЕсли Найти(Строка(Колонка.ТипЗначения), "Число") > 0 Тогда
Файл.Поля.Добавить(Лев(Колонка.Имя, 10), "N", 15, 3);
КолонкаТиповая = Истина;
ИначеЕсли Найти(Строка(Колонка.ТипЗначения), "Дата") > 0 Тогда
Файл.Поля.Добавить(Лев(Колонка.Имя, 10), "D");
КолонкаТиповая = Истина;
КонецЕсли;
Если НЕ КолонкаТиповая Тогда
// Для прочих типов создаем строковое поле ограниченной длины
Файл.Поля.Добавить(Лев(Колонка.Имя, 10), "S", 254);
КонецЕсли;
Исключение
Сообщить("Колонка """ + Колонка.Имя + """ не создана. Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Файл.ОткрытьФайл(ПолныйПутьКФайлуDBF);
Если Не Файл.Открыта() Тогда
Файл.СоздатьФайл(ПолныйПутьКФайлуDBF);
Иначе
Файл.ОчиститьФайл();
КонецЕсли;
Возврат Файл;
КонецФункции
При получении таблицы значений через ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений важно учитывать следующие нюансы:
КомпоновщикНастроек.Настройки используйте вызов КомпоновщикНастроек.ПолучитьНастройки(). Это гарантирует, что установленные пользователем на форме отборы и параметры применятся к выгрузке.