Интеграция со сторонними информационными системами часто ставит перед разработчиком 1С задачу импорта данных из файлов устаревших форматов, таких как DBF. Несмотря на возраст стандарта, таблицы DBF активно используются для обмена данными в различных отраслях. В этой статье мы подробно разберем, как прочитать данные из файла DBF и оптимально перенести их в коллекции 1С — массивы, структуры или таблицы значений. Мы также проанализируем скрытые технические проблемы, с которыми вы гарантированно столкнетесь на практике, и найдем пути их решения.
Платформа 1С:Предприятие предоставляет стандартный встроенный объект XBase, специально предназначенный для прямой работы с файлами баз данных dBase. Это наиболее быстрый и кроссплатформенный инструмент, не требующий установки дополнительных драйверов в операционной системе.
Рассмотрим по шагам классический пример считывания данных. Допустим, у нас есть файл DBF, содержащий три колонки (например, "Колонка1", "Колонка2", "Колонка3"), и нам необходимо выгрузить эти данные в массив структур для последующего сравнения со строками табличной части документа.
Применим следующий эффективный алгоритм:
// Создаем объект для работы с файлом DBF
ДБФ = Новый XBase;
// Открываем файл по указанному пути
ДБФ.ОткрытьФайл(ПутьКФайлу);
Если Не ДБФ.Открыта() Тогда
ВызватьИсключение "Не удалось открыть файл DBF. Проверьте правильность пути и права доступа.";
КонецЕсли;
// Подготовим массив для хранения результатов
МассивРезультатов = Новый Массив;
// Переходим к первой записи файла
ДБФ.Первая();
// Запускаем цикл обхода всех записей файла
Пока Не ДБФ.ВКонце() Цикл
// Для удобства последующей обработки строки создаем Структуру
СтрокаДанных = Новый Структура;
СтрокаДанных.Вставить("Колонка1", ДБФ.Колонка1);
СтрокаДанных.Вставить("Колонка2", ДБФ.Колонка2);
СтрокаДанных.Вставить("Колонка3", ДБФ.Колонка3);
// Добавляем заполненную структуру в результирующий массив
МассивРезультатов.Добавить(СтрокаДанных);
// Переходим к следующей записи
ДБФ.Следующая();
КонецЦикла;
// Закрываем файл после завершения операции, чтобы освободить системные ресурсы
ДБФ.ЗакрытьФайл();
Важное архитектурное замечание: Если в дальнейшем вам потребуется сопоставить полученные данные с элементами табличной части, использование массива структур является идеальным решением. В цикле обхода табличной части вы сможете легко использовать метод платформы ЗаполнитьЗначенияСвойств(), сопоставив свойства структуры с реквизитами строки вашей таблицы.
Если вам нужно получить массив значений только по одной определенной колонке файла, ручной обход в цикле может оказаться избыточным и медленным. В таком случае гораздо рациональнее сначала считать всю таблицу DBF во временную ТаблицаЗначений, а затем выгрузить нужную колонку в одно действие с помощью встроенного высокопроизводительного метода платформы.
Разберем этот вариант реализации:
// Создаем Таблицу Значений и описываем её структуру
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Колонка1");
ТаблицаДанных.Колонки.Добавить("Колонка2");
ТаблицаДанных.Колонки.Добавить("Колонка3");
ДБФ = Новый XBase;
ДБФ.ОткрытьФайл(ПутьКФайлу);
Если ДБФ.Открыта() Тогда
ДБФ.Первая();
Пока Не ДБФ.ВКонце() Цикл
НоваяСтрока = ТаблицаДанных.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ДБФ);
ДБФ.Следующая();
КонецЦикла;
ДБФ.ЗакрытьФайл();
КонецЕсли;
// Быстрое получение плоского массива значений по конкретной колонке
МассивЭлементов = ТаблицаДанных.ВыгрузитьКолонку("Колонка1");
Метод ВыгрузитьКолонку() реализован на уровне платформы на языке C++ и выполняется значительно быстрее, чем ручное наполнение массива поэлементно в цикле на встроенном языке 1С.
При использовании стандартного объекта XBase программисты часто сталкиваются со следующей неочевидной ошибкой: метод ОткрытьФайл() возвращает ложь, хотя файл гарантированно существует на диске и права доступа к нему открыты.
Выясним причину проблемы: Внутренний движок встроенного объекта XBase в 1С унаследовал логику работы устаревших DOS-библиотек СУБД dBase. Из-за этого он критически зависит от ограничений файловой системы на длину имен папок и файлов. Формат DOS 8.3 требует, чтобы имя файла содержало не более 8 символов, а его расширение — не более 3 символов. Длина путей к файлу также может вызывать сбои.
Решать проблему обрезкой длины имени сгенерированного временного файла до 8 символов (например, через Лев(Новый УникальныйИдентификатор(), 8)) небезопасно, так как при многопоточной работе на сервере возрастает риск коллизии имен файлов.
Разберем наиболее стабильное и безопасное решение этой проблемы:
data.dbf (всего 4 символа в имени).Посмотрим на программную реализацию этого обхода ограничений:
// Формируем путь к уникальной временной папке
ИмяВременнойПапки = КаталогВременныхФайлов() + Новый УникальныйИдентификатор() + "\";
СоздатьКаталог(ИмяВременнойПапки);
// Копируем исходный файл в эту папку под коротким именем "data.dbf"
ВременныйФайлDBF = ИмяВременнойПапки + "data.dbf";
КопироватьФайл(ИсходныйПутьКФайлу, ВременныйФайлDBF);
// Теперь безопасно открываем XBase
ДБФ = Новый XBase;
ДБФ.ОткрытьФайл(ВременныйФайлDBF);
// [Здесь выполняется ваш алгоритм чтения данных]
ДБФ.ЗакрытьФайл();
// Обязательно наводим за собой порядок на диске
Попытка
УдалитьФайлы(ИмяВременнойПапки);
Исключение
ЗаписьЖурналаРегистрации("УдалениеВременныхФайлов", УровеньЖурналаРегистрации.Предупреждение,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Многие разработчики ошибочно полагают, что встроенный объект 1С XBase вообще не умеет работать со специальными текстовыми неограниченными MEMO-полями. Проанализируем эту ситуацию детальнее.
На самом деле, встроенный XBase поддерживает чтение MEMO-полей, но накладывает жесткие ограничения на их форматы:
.dbt должен обязательно находиться в той же директории, что и основной файл .dbf..dbt должно быть абсолютно идентичным имени файла .dbf (различаться должны только расширения).Если же ваша таблица DBF создана СУБД Microsoft FoxPro (или Visual FoxPro), то MEMO-поля там хранятся в формате .fpt. Этот формат встроенным объектом XBase платформы 1С **не поддерживается**. Попытка прочитать такое поле приведет либо к ошибке выполнения, либо к чтению пустых значений. Если вы столкнулись именно с этой проблемой, вам поможет переход на технологию ADO.
Использование технологии ADO позволяет обойти абсолютно все системные ограничения встроенного 1С-объекта XBase. При работе через COM-объект ADODB.Connection вы получаете следующие преимущества:
.fpt) при наличии установленного провайдера Microsoft Visual FoxPro OLE DB Provider.Рассмотрим по шагам программный пример чтения данных через ADO:
// Создаем COM-объект подключения
Connection = Новый COMОбъект("ADODB.Connection");
// Обратите внимание: Источником данных (Data Source) для провайдера DBF
// является именно каталог (папка), в котором лежит файл, а не сам файл!
РазделительПути = "/";
Если Найти(ПутьКФайлу, "\") > 0 Тогда
РазделительПути = "\";
КонецЕсли;
ПозицияПоследнегоСлэша = СтрНайти(ПутьКФайлу, РазделительПути, НаправлениеПоиска.ОтКонца);
КаталогФайла = Лев(ПутьКФайлу, ПозицияПоследнегоСлэша);
ИмяФайлаDBF = Сред(ПутьКФайлу, ПозицияПоследнегоСлэша + 1);
// Формируем строку подключения для провайдера Jet OLEDB
СтрокаПодключения = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + КаталогФайла + ";Extended Properties=dBASE IV;";
Попытка
Connection.Open(СтрокаПодключения);
Исключение
ВызватьИсключение "Не удалось установить соединение через ADO: " + ОписаниеОшибки();
КонецПопытки;
// Выполняем SQL-запрос к файлу, имя файла выступает в роли имени таблицы в БД
ТекстЗапроса = "SELECT Колонка1, Колонка2, Колонка3 FROM [" + ИмяФайлаDBF + "]";
Recordset = Новый COMОбъект("ADODB.Recordset");
Попытка
Recordset.Open(ТекстЗапроса, Connection, 3, 1); // CursorType: adOpenStatic, LockType: adLockReadOnly
Исключение
Connection.Close();
ВызватьИсключение "Ошибка выполнения SQL-запроса к DBF: " + ОписаниеОшибки();
КонецПопытки;
МассивРезультатов = Новый Массив;
// Обходим полученный набор записей
Пока Recordset.EOF = 0 Цикл
СтрокаДанных = Новый Структура;
СтрокаДанных.Вставить("Колонка1", Recordset.Fields("Колонка1").Value);
СтрокаДанных.Вставить("Колонка2", Recordset.Fields("Колонка2").Value);
СтрокаДанных.Вставить("Колонка3", Recordset.Fields("Колонка3").Value);
МассивРезультатов.Добавить(СтрокаДанных);
Recordset.MoveNext();
КонецЦикла;
// Закрываем соединения
Recordset.Close();
Connection.Close();
В современных реалиях построения ИТ-архитектуры серверная часть платформы 1С:Предприятие очень часто функционирует под управлением операционных систем семейства Linux. Это накладывает серьезный отпечаток на выбор способа интеграции.
Важное предупреждение: Использование технологии ADO (COM-объектов Windows) на сервере Linux принципиально невозможно. Попытка вызова Новый COMОбъект("ADODB.Connection") на Linux-сервере приведет к немедленному аварийному завершению работы программы с системной ошибкой.
Напротив, встроенный объект 1С XBase начиная с платформы 8.3 полностью переписан разработчиками 1С и нативно поддерживается как в Windows, так и во всех поддерживаемых 64-битных дистрибутивах Linux.
Однако при работе с XBase на Linux-сервере возникает другая критически важная деталь — чувствительность к регистру символов (case-sensitivity) в именах файлов и путей. Если в ОС Windows вы могли передать в метод ОткрытьФайл() путь /temp/MyData.dbf, а сам файл на диске назывался /temp/mydata.DBF, Windows успешно проигнорирует разницу регистров и откроет файл. В среде Linux такое обращение вызовет неустранимую ошибку "Файл не найден". Всегда строго контролируйте регистр написания имен файлов и расширений в коде вашей конфигурации!