Чтение таблиц DBF в 1С 8.3: рабочий код и разбор проблем
Содержание
Прочитать DBF файл в 1С проще всего встроенным объектом XBase: открываете файл методом ОткрытьФайл(), задаёте кодировку и идёте по записям циклом Пока Не ВКонце(). Внешние компоненты не нужны, код работает и в файловой, и в клиент-серверной базе. Второй путь — COM: ADO-соединение через провайдер Visual FoxPro или Access Database Engine. Он нужен, когда XBase не понимает формат, например таблицы Visual FoxPro с типами Integer или DateTime.
На практике 80 строк кода закрывают почти все задачи: выписки банков, справочники ФИАС/КЛАДР старого образца, выгрузки из старых учётных программ. Основные грабли — кодировка, memo-файлы и разрядность провайдеров. Всё это ниже, с кодом.
Объект XBase: что умеет платформа без сторонних средств
XBase — объект встроенного языка для работы с файлами формата dBase. Он открывает, читает, создаёт и правит таблицы, умеет работать с индексами .cdx.
Главное, что нужно знать перед чтением:
- 📄 Где доступен. На сервере, в толстом клиенте и во внешнем соединении. В тонком клиенте и веб-клиенте объекта нет, поэтому читать DBF из управляемой формы нужно в серверной процедуре.
- 🔤 Кодировка. Свойство
КодировкапринимаетКодировкаXBase.OEM(DOS, cp866) илиКодировкаXBase.ANSI(Windows-1251). По умолчанию стоит ANSI. - 📎 Memo-поля. Хранятся в отдельном файле
.dbtрядом с таблицей. Если его нет или у него другое имя, файл не откроется. - 🗑 Удалённые записи. В DBF удаление — это пометка, запись физически остаётся до упаковки таблицы. Отсечь её помогает метод
ЗаписьУдалена().
Ключевые методы для чтения:
| Метод / свойство | Что делает |
|---|---|
ОткрытьФайл(Имя, Индекс, ТолькоЧтение) | Открывает таблицу. Третий параметр Истина — только чтение |
Открыта() | Возвращает Истина, если файл открыт |
Поля | Коллекция полей: у каждого есть Имя, Тип, Длина, Точность |
Первая(), Следующая() | Перемещение по записям |
ВКонце() | Истина, когда записи закончились |
ПолучитьЗначениеПоля(ИмяИлиНомер) | Значение поля текущей записи |
КоличествоЗаписей() | Число записей в файле |
ЗакрытьФайл() | Освобождает файл |
К полю можно обратиться и как к свойству: DBF.NAME. Это удобно, когда структура файла известна заранее. Для универсальной загрузки лучше ПолучитьЗначениеПоля() — имя поля передаётся строкой.
Типы dBase переводятся в типы 1С так:
| Тип в DBF | Код | Что вернёт 1С |
|---|---|---|
| Символьный | C | Строка (с хвостовыми пробелами) |
| Числовой | N, F | Число |
| Дата | D | Дата |
| Логический | L | Булево |
| Memo | M | Строка |
Символьные поля в DBF дополняются пробелами до полной длины. Поле длиной 40 символов с текстом «ООО Ромашка» вернётся строкой из 40 символов. Всегда обрезайте значение через СокрП(), иначе поиск по наименованию в справочниках не найдёт совпадений.
Как прочитать DBF файл в 1С кодом: загрузка в таблицу значений
Ниже универсальная функция: она читает любой DBF в таблицу значений, колонки создаёт по полям файла. Структуру заранее знать не нужно.
&НаСервереБезКонтекста
Функция ПрочитатьDBF(ИмяФайла, Кодировка)
ТЗ = Новый ТаблицаЗначений;
DBF = Новый XBase;
DBF.Кодировка = Кодировка;
DBF.ОткрытьФайл(ИмяФайла, , Истина);
Если Не DBF.Открыта() Тогда
ВызватьИсключение "Не удалось открыть файл " + ИмяФайла;
КонецЕсли;
Для Каждого Поле Из DBF.Поля Цикл
ТЗ.Колонки.Добавить(Поле.Имя);
КонецЦикла;
DBF.Первая();
Пока Не DBF.ВКонце() Цикл
Если Не DBF.ЗаписьУдалена() Тогда
НоваяСтрока = ТЗ.Добавить();
Для Каждого Поле Из DBF.Поля Цикл
Значение = DBF.ПолучитьЗначениеПоля(Поле.Имя);
Если ТипЗнч(Значение) = Тип("Строка") Тогда
Значение = СокрП(Значение);
КонецЕсли;
НоваяСтрока[Поле.Имя] = Значение;
КонецЦикла;
КонецЕсли;
DBF.Следующая();
КонецЦикла;
DBF.ЗакрытьФайл();
Возврат ТЗ;
КонецФункции
Передача файла с клиента на сервер
В клиент-серверной базе путь C:\Выписки\bank.dbf на компьютере пользователя сервер не видит. Файл сначала помещают во временное хранилище, а на сервере записывают во временный каталог:
&НаКлиенте
Процедура ЗагрузитьDBF(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДопПараметры) Экспорт
Если Результат Тогда
ЗагрузитьНаСервере(Адрес);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьНаСервере(Адрес)
ДД = ПолучитьИзВременногоХранилища(Адрес);
ИмяФайла = ПолучитьИмяВременногоФайла("dbf");
ДД.Записать(ИмяФайла);
ТЗ = ПрочитатьDBF(ИмяФайла, КодировкаXBase.OEM);
УдалитьФайлы(ИмяФайла);
Для Каждого Строка Из ТЗ Цикл
// обработка строки: поиск контрагента, создание документа и т.п.
КонецЦикла;
КонецПроцедуры
Таблица с memo-полями
У временного файла случайное имя, поэтому парный .dbt с ним не свяжется. Если в таблице есть memo-поля, поступайте так:
- На сервере создайте временный каталог:
Каталог = ПолучитьИмяВременногоФайла(""); СоздатьКаталог(Каталог);. - Запишите туда оба файла под одним базовым именем:
data.dbfиdata.dbt. - Откройте
data.dbfобъектомXBase. - После чтения удалите каталог целиком:
УдалитьФайлы(Каталог);.
С клиента оба файла передаются одним вызовом множественного помещения или двумя вызовами НачатьПомещениеФайла.
Чтение DBF через COM: Visual FoxPro OLE DB и ADO
COM-путь нужен, когда файл создан в Visual FoxPro и использует типы, которых нет в классическом dBase: I (целое), Y (денежный), T (дата-время), B (двойная точность). Ещё один повод — SQL-запросы с отбором прямо к файлу.
Работает только под Windows. Варианты провайдеров:
| Провайдер | Строка подключения | Разрядность |
|---|---|---|
| Visual FoxPro OLE DB | Provider=VFPOLEDB.1;Data Source=C:\Data\; | только 32 бит |
| Access Database Engine | Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Data\;Extended Properties=dBASE IV; | 32 и 64 бит |
| ODBC dBase | Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=C:\Data\; | 32 бит |
Data Source — это каталог, а не файл. Таблица указывается в тексте запроса.
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Open("Provider=VFPOLEDB.1;Data Source=C:\Data\;");
Выборка = Новый COMОбъект("ADODB.Recordset");
Выборка.Open("SELECT * FROM bank.dbf WHERE summa > 0", Соединение);
Пока Не Выборка.EOF Цикл
Счет = СокрП(Выборка.Fields("SCHET").Value);
Сумма = Выборка.Fields("SUMMA").Value;
// обработка значений
Выборка.MoveNext();
КонецЦикла;
Выборка.Close();
Соединение.Close();
Провайдер Visual FoxPro существует только в 32-битной версии. Если код выполняется на 64-битном сервере 1С или в 64-битном клиенте, ADO выдаст Провайдер не найден. Возможно, он установлен неправильно. (в английской Windows — Provider cannot be found. It may not be properly installed.). Выход: 32-битный клиент с чтением на клиенте, либо Access Database Engine x64.
Чтение на сервере через COM требует установки провайдера на каждый рабочий сервер кластера. В файловой базе — на каждый компьютер, где запускают загрузку.
Кодировка DBF: OEM, ANSI и нечитаемые символы
Кириллица в DBF хранится в одной из двух кодировок:
- 🖥 cp866 (OEM, DOS) — файлы из старых DOS-программ, банковских систем, Клиент-Банков, ФИАС/КЛАДР.
- 🪟 Windows-1251 (ANSI) — файлы из Windows-приложений, Excel, FoxPro для Windows.
Если в результате вместо «Иванов» видите €ў ®ў или похожий набор символов, кодировка выбрана неправильно. Поменяйте КодировкаXBase.OEM на КодировкаXBase.ANSI или наоборот.
Как определить кодировку автоматически
В заголовке DBF по смещению 29 лежит байт кодовой страницы (Language Driver ID). Типичные значения для русских файлов: 0x65 (101) — cp866, 0xC9 (201) — Windows-1251. Многие программы оставляют там ноль, тогда остаётся проверка на тексте.
Надёжный приём: прочитайте первую запись в OEM и посчитайте долю русских букв в символьных полях. Если доля близка к нулю, а символов вроде Ђ, ў, много — переоткройте в ANSI. Для банковских выписок кодировку проще один раз зафиксировать в настройках загрузки.
В ADO-провайдере Visual FoxPro кодировка берётся из того же байта заголовка. Если он пустой, а текст в файле в cp866, русские строки придут искажёнными. Тогда проще читать файл объектом XBase с явной кодировкой.
Если XBase не открывает файл: проверяем заголовок
Когда ОткрытьФайл() падает с ошибкой, стоит заглянуть в первые байты файла. Объект ЧтениеДанных (платформа 8.3.9 и выше) читает заголовок без сторонних утилит:
Чтение = Новый ЧтениеДанных(ИмяФайла);
Версия = Чтение.ПрочитатьБайт(); // байт 0: тип файла
Чтение.Пропустить(3); // байты 1-3: дата изменения
ЧислоЗаписей = Чтение.ПрочитатьЦелое32(); // байты 4-7
ДлинаЗаголовка = Чтение.ПрочитатьЦелое16(); // байты 8-9
ДлинаЗаписи = Чтение.ПрочитатьЦелое16(); // байты 10-11
Чтение.Пропустить(17); // байты 12-28
КодоваяСтраница = Чтение.ПрочитатьБайт(); // байт 29
Чтение.Закрыть();
Как расшифровать первый байт:
| Значение | Формат | Что делать |
|---|---|---|
0x03 | dBase III без memo | Читается XBase |
0x83 | dBase III с memo .dbt | XBase, рядом должен лежать .dbt |
0x30 | Visual FoxPro | ADO через VFPOLEDB или ACE |
0xF5 | FoxPro с memo .fpt | ADO через VFPOLEDB |
Заодно сверьте размер: длина заголовка + число записей × длина записи должны примерно совпадать с размером файла (плюс 1 байт конца файла). Сильное расхождение — признак обрезанного при передаче файла.
Какой способ чтения DBF выбрать
| Критерий | XBase | ADO / COM |
|---|---|---|
| Установка | Ничего не нужно | Провайдер на каждом компьютере или сервере |
| ОС сервера | Windows и Linux | Только Windows |
| Форматы | dBase III/IV, memo .dbt | Плюс Visual FoxPro, .fpt, новые типы полей |
| Отбор записей | Перебором в цикле | SQL WHERE прямо в запросе |
| Кодировка | Задаётся явно | Из заголовка файла |
| Тонкий клиент | Только через сервер | Работает на клиенте под Windows |
| Запись в файл | Да | Да, через INSERT/UPDATE |
Короткое правило: начинайте с XBase. На COM переходите, только если файл не открывается или нужен SQL. Для базы на Linux-сервере COM недоступен вовсе.
Если не помогло ни то, ни другое
Откройте DBF в LibreOffice Calc: при открытии он спрашивает кодировку, можно перебрать варианты и увидеть читаемый текст. Затем сохраните как .xlsx и загрузите через ТабличныйДокумент.Прочитать() или типовую загрузку из файла. Для разовой задачи это быстрее, чем отлаживать провайдер.
Обработка ошибок при чтении DBF
Файл должен закрываться в любом случае, даже при сбое на середине. Иначе он остаётся занятым процессом 1С до перезапуска сеанса или рабочего процесса.
DBF = Новый XBase;
DBF.Кодировка = КодировкаXBase.OEM;
Попытка
DBF.ОткрытьФайл(ИмяФайла, , Истина);
// ... чтение записей ...
DBF.ЗакрытьФайл();
Исключение
Текст = ОписаниеОшибки();
Если DBF.Открыта() Тогда
DBF.ЗакрытьФайл();
КонецЕсли;
ЗаписьЖурналаРегистрации("Загрузка DBF", УровеньЖурналаРегистрации.Ошибка, , , Текст);
ВызватьИсключение "Не удалось прочитать " + ИмяФайла + ": " + Текст;
КонецПопытки;
Ситуации, которые встречаются чаще всего:
Если код не только читает, но и пишет в DBF, работайте с копией файла. Сбой посреди записи может испортить заголовок, и исходная таблица перестанет открываться.
Для больших файлов, от сотен тысяч записей, не собирайте всё в одну таблицу значений на сервере. Обрабатывайте записи прямо в цикле или пачками по 1 000–5 000 строк с записью объектов в отдельных транзакциях. Так вы не упрётесь в память рабочего процесса.