Работа с DBF в 1С делается встроенным объектом XBase: он открывает существующий файл или создаёт новый, позволяет перебирать записи, читать и записывать поля, удалять строки и использовать индексы. Ничего устанавливать не нужно, и работает он одинаково на Windows и Linux. Главное, о чём надо помнить, — кодировка (OEM или ANSI) и то, что код выполняется на сервере, поэтому файл туда нужно передать.

Формат DBF давно устарел, но всё ещё встречается: выгрузки банков и казначейства, справочники ФИАС/КЛАДР в старых версиях, обмен с программами на FoxPro и Clipper, отчётность в фонды. Ниже — как читать и создавать такие файлы, какие бывают ловушки и когда может понадобиться ADO.

Как устроен DBF-файл

Работа с DBF в 1С: заголовок файла, записи фиксированной длины и индекс
Работа с DBF в 1С: заголовок файла, записи фиксированной длины и индекс

DBF состоит из заголовка и таблицы записей:

  • Заголовок — версия формата, количество записей, длина записи и описание полей: имя (до 10 символов), тип, длина, точность.
  • Записи — строки фиксированной длины. Удалённая запись не стирается, а помечается флагом удаления.
  • Индексные файлы (.cdx, .ntx, .mdx и др.) — отдельно, для быстрого поиска по ключу.

Единого стандарта у формата нет: dBase, FoxPro, Clipper добавляли свои типы полей и расширения заголовка. Базовые типы — строка, число, дата, логическое — читаются везде, экзотические (memo-поля в отдельных файлах, специфичные типы FoxPro) могут вызвать проблемы.

Чтение DBF через XBase

Типовая задача — загрузить файл в таблицу значений и дальше работать с ней обычными средствами.

1С
// Читает DBF-файл и возвращает таблицу значений с колонками по полям файла.
Функция ПрочитатьDBF(ИмяФайла, КодировкаOEM = Истина) Экспорт

	Файл = Новый XBase;
	Файл.Кодировка = ?(КодировкаOEM, КодировкаXBase.OEM, КодировкаXBase.ANSI);
	Файл.ОткрытьФайл(ИмяФайла, , Истина); // только чтение

	Если Не Файл.Открыта() Тогда
		ВызватьИсключение СтрШаблон("Не удалось открыть файл %1", ИмяФайла);
	КонецЕсли;

	Результат = Новый ТаблицаЗначений;
	Для Каждого Поле Из Файл.Поля Цикл
		Результат.Колонки.Добавить(Поле.Имя);
	КонецЦикла;

	Попытка
		ЕстьЗапись = Файл.Первая();
		Пока ЕстьЗапись Цикл
			Если Не Файл.ЗаписьУдалена() Тогда
				Строка = Результат.Добавить();
				Для Каждого Поле Из Файл.Поля Цикл
					Значение = Файл.ПолучитьЗначениеПоля(Поле.Имя);
					Строка[Поле.Имя] = ?(ТипЗнч(Значение) = Тип("Строка"), СокрЛП(Значение), Значение);
				КонецЦикла;
			КонецЕсли;
			ЕстьЗапись = Файл.Следующая();
		КонецЦикла;
	Исключение
		Файл.ЗакрытьФайл();
		ВызватьИсключение;
	КонецПопытки;

	Файл.ЗакрытьФайл();
	Возврат Результат;

КонецФункции

Пояснения:

  • Кодировку задавайте до открытия файла. Иначе строки прочитаются с неверной кодовой страницей.
  • Строковые поля дополнены пробелами до длины поля — отсюда СокрЛП.
  • Удалённые записи. По умолчанию XBase их не показывает (свойство ОтображатьУдаленные), но явная проверка ЗаписьУдалена не повредит, если кто-то включил отображение.
  • Количество записей можно получить методом КоличествоЗаписей() — удобно для индикатора прогресса.

Создание DBF-файла

Обратная задача — выгрузить данные в DBF для внешней программы.

1С
// Выгружает список контрагентов в DBF-файл в кодировке ANSI.
Процедура ВыгрузитьКонтрагентовВDBF(ИмяФайла, Контрагенты) Экспорт

	Файл = Новый XBase;
	Файл.Кодировка = КодировкаXBase.ANSI;

	// Имена полей — латиница, не длиннее 10 символов
	Файл.Поля.Добавить("INN", "S", 12);
	Файл.Поля.Добавить("NAME", "S", 150);
	Файл.Поля.Добавить("DEBT", "N", 15, 2);
	Файл.Поля.Добавить("REGDATE", "D");
	Файл.Поля.Добавить("ACTIVE", "L");

	Файл.СоздатьФайл(ИмяФайла);

	Попытка
		Для Каждого Строка Из Контрагенты Цикл
			Файл.Добавить();
			Файл.INN = Строка.ИНН;
			Файл.NAME = Лев(Строка.Наименование, 150);
			Файл.DEBT = Строка.Задолженность;
			Файл.REGDATE = Строка.ДатаРегистрации;
			Файл.ACTIVE = Строка.Активен;
			Файл.Записать();
		КонецЦикла;
	Исключение
		Файл.ЗакрытьФайл();
		ВызватьИсключение;
	КонецПопытки;

	Файл.ЗакрытьФайл();

КонецПроцедуры

Типы полей задаются буквами: S — строка, N — число (длина и точность), D — дата, L — логическое. Значения полей текущей записи доступны как свойства объекта по имени поля. Строки длиннее поля обрезаются — лучше сделать это явно через Лев, чтобы не гадать, что попадёт в файл.

Если получатель ожидает конкретную структуру (как в отчётности или банковских форматах), сверяйте имена, типы, длины и кодировку с его спецификацией — по ним файл и будут проверять.

Индексы и поиск

XBase умеет создавать индексные файлы и искать по ключу: индексы описываются в коллекции Индексы, создаются методом СоздатьИндексныйФайл, а поиск выполняется методом Найти по текущему индексу. Для разовой загрузки это обычно лишнее: проще прочитать файл в таблицу значений и искать в ней. Индексы оправданы, когда файл большой, а нужно найти несколько записей, или когда внешняя программа требует индексный файл рядом с DBF.

Работа на сервере и передача файла

XBase работает с файлами на том компьютере, где выполняется код, и в тонком клиенте недоступен. Типичная схема загрузки:

  1. На клиенте пользователь выбирает файл (НачатьПомещениеФайлаНаСервер или аналог) — файл попадает во временное хранилище.
  2. На сервере данные из хранилища записываются во временный файл (ПолучитьИмяВременногоФайла("dbf")).
  3. Файл читается через XBase, временный файл удаляется.

Для выгрузки — наоборот: формируете файл на сервере, читаете его как ДвоичныеДанные, помещаете во временное хранилище и отдаёте пользователю.

ADO: когда может понадобиться

Альтернатива — доступ к DBF через ADO (COMОбъект("ADODB.Connection")) с OLE DB-провайдером и SQL-запросами к папке с файлами. Основные объекты: Connection (подключение, строка вида Provider=…;Data Source=<папка>;Extended Properties=dBASE IV), Recordset (набор записей с навигацией MoveNext, EOF) и Command (выполнение SQL).

Плюс подхода — SQL: выборка с условиями и агрегатами без перебора в коде. Минусы перевешивают:

  • работает только на Windows;
  • провайдер Microsoft.Jet.OLEDB.4.0 существует только в 32-битном варианте и не подключится в 64-битном сервере 1С; нужен провайдер ACE или драйвер нужной разрядности;
  • драйвер надо устанавливать на сервер, а права службы 1С — настраивать на папку.

На практике я использую ADO для DBF только тогда, когда нужно сложное SQL-условие по очень большому файлу, а сервер — Windows. В остальных случаях XBase проще и надёжнее.

Типичные ошибки

  • Нечитаемые символы. Кодировка не та: попробуйте OEM вместо ANSI или наоборот, и задавайте её до открытия файла.
  • «Файл не найден» на сервере. Путь указан к файлу на компьютере пользователя. Передайте файл на сервер через временное хранилище.
  • Длинные имена полей. Имена больше 10 символов или кириллица в именах полей — внешние программы такой файл не прочитают.
  • Пустые даты. Пустая дата в DBF читается как пустая дата 1С (Дата(1, 1, 1)); при выгрузке убедитесь, что получатель понимает пустое значение.
  • Файл заблокирован. Не закрыли файл при исключении — следующий запуск не сможет его открыть. Закрывайте в обработке исключений.
  • Memo-поля. Хранятся в отдельном файле (.dbt, .fpt). Без него поле прочитать не получится.
DBF — простой формат с непростой историей. Сначала узнайте у источника кодировку и структуру, и только потом пишите загрузку.

Загрузки из DBF, банковских и других «наследных» форматов делаю в рамках доработки 1С и интеграции 1С; если DBF — лишь промежуточный файл между двумя базами 1С, правильнее настроить прямой обмен между базами.

Итог

  • Работа с DBF в 1С выполняется объектом XBase — без внешних драйверов, на любом сервере.
  • Кодировку (КодировкаXBase.OEM или ANSI) задавайте до открытия файла.
  • Для чтения перебирайте записи Первая/Следующая и берите значения через ПолучитьЗначениеПоля; для записи — Поля.Добавить, СоздатьФайл, Добавить, Записать.
  • Код выполняется на сервере: передавайте файл через временное хранилище.
  • ADO — только для Windows и с драйвером нужной разрядности.