Выгрузка данных из 1С в DBF: XBase, ADO и запись по байтам
Содержание
Создать файл DBF в 1С проще всего встроенным объектом XBase: описываете поля через Поля.Добавить(), вызываете СоздатьФайл(), в цикле делаете Добавить() и Записать(), в конце ЗакрытьФайл(). Внешние драйверы не нужны, объект есть в платформе 8.3. Работает он на сервере и в толстом клиенте, поэтому код пишут в серверной процедуре, а готовый файл передают пользователю.
Если нужен формат, который XBase не даёт, остаются три пути: COM-объект ADODB.Connection и SQL-команды, внешняя обработка с универсальной выгрузкой и ручная сборка файла по байтам через ЗаписьДанных. Ниже каждый способ с рабочим кодом и подводными камнями.
Где сегодня нужен DBF и какой метод выбрать
DBF давно устарел, но его до сих пор требуют:
- 🏦 банки — реестры на зачисление зарплаты и реестры платежей по старым форматам;
- 🏢 управляющие компании и расчётные центры — выгрузки лицевых счетов и начислений;
- 🧾 старые программы на FoxPro и Clipper, которые до сих пор работают у контрагентов;
- 🗺 ГИС-системы: атрибуты карт в формате Shapefile хранятся именно в DBF.
Способы отличаются тем, что нужно поставить на компьютер и насколько точно вы управляете форматом.
| Метод | Когда подходит | Что нужно | Риски |
|---|---|---|---|
Объект XBase | почти всегда | ничего, есть в платформе | только сервер и толстый клиент |
COM ADODB + SQL | нужен FoxPro-формат или SQL-логика | провайдер OLE DB на машине, где идёт код | разрядность 32/64, зависимость от Windows |
| Внешняя обработка | выгрузка повторяется, нужна форма | права на внешние обработки | обработку надо сопровождать |
| Запись по байтам | приёмник капризен к заголовку | платформа 8.3.9 и новее | ошибка в длине ломает весь файл |
Создание DBF через объект XBase
Это основной способ. Объект XBase создаёт таблицу формата dBASE и пишет в неё записи. Поля описывают четырьмя параметрами: имя, тип, длина, точность.
Типы полей в XBase:
"S"— строка, длина до 254 символов;"N"— число, длина считается вместе со знаком и десятичной точкой;"D"— дата, хранится без времени;"L"— булево;"M"— длинный текст; рядом с DBF появляется отдельный memo-файл, и передавать нужно оба.
Имя поля — не длиннее 10 символов, латиницей. Кириллица в именах полей формально записывается, но большинство программ-приёмников такой файл не прочтёт.
Серверная часть: формируем файл
Пример выгружает справочник контрагентов из 1С:Бухгалтерии 3.0 в форму внешней обработки.
&НаСервере
Функция СоздатьDBFНаСервере()
ИмяФайла = ПолучитьИмяВременногоФайла("dbf");
ДБФ = Новый XBase;
ДБФ.Кодировка = КодировкаXBase.OEM;
ДБФ.Поля.Добавить("NPP", "N", 6, 0);
ДБФ.Поля.Добавить("CODE", "S", 20);
ДБФ.Поля.Добавить("NAME", "S", 100);
ДБФ.Поля.Добавить("INN", "S", 12);
ДБФ.Поля.Добавить("DELETED", "L");
ДБФ.Поля.Добавить("EXPDATE", "D");
ДБФ.СоздатьФайл(ИмяФайла);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Код КАК Код,
| Контрагенты.Наименование КАК Наименование,
| Контрагенты.ИНН КАК ИНН,
| Контрагенты.ПометкаУдаления КАК ПометкаУдаления
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| НЕ Контрагенты.ЭтоГруппа";
Выборка = Запрос.Выполнить().Выбрать();
НомерСтроки = 0;
Пока Выборка.Следующий() Цикл
НомерСтроки = НомерСтроки + 1;
ДБФ.Добавить();
ДБФ.NPP = НомерСтроки;
ДБФ.CODE = СокрЛП(Выборка.Код);
ДБФ.NAME = Лев(Выборка.Наименование, 100);
ДБФ.INN = Выборка.ИНН;
ДБФ.DELETED = Выборка.ПометкаУдаления;
ДБФ.EXPDATE = ТекущаяДатаСеанса();
ДБФ.Записать();
КонецЦикла;
ДБФ.ЗакрытьФайл();
Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайла), УникальныйИдентификатор);
УдалитьФайлы(ИмяФайла);
Возврат Адрес;
КонецФункции
ЗакрытьФайл() обязателен до чтения файла в ДвоичныеДанные. Пока файл открыт, в заголовке может стоять старое число записей, и приёмник увидит пустую таблицу.
Клиентская часть: отдаём файл пользователю
В клиент-серверном варианте файл создаётся во временном каталоге сервера 1С. Пользователь его не видит, поэтому файл передают через временное хранилище.
&НаКлиенте
Процедура ВыгрузитьВDBF(Команда)
Адрес = СоздатьDBFНаСервере();
ПолучаемыеФайлы = Новый Массив;
ПолучаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла("kontragenty.dbf", Адрес));
НачатьПолучениеФайлов(Новый ОписаниеОповещения("ПослеСохраненияФайла", ЭтотОбъект),
ПолучаемыеФайлы, , Истина);
КонецПроцедуры
&НаКлиенте
Процедура ПослеСохраненияФайла(ПолученныеФайлы, ДополнительныеПараметры) Экспорт
Если ПолученныеФайлы <> Неопределено Тогда
ПоказатьОповещениеПользователя("Файл DBF сохранён");
КонецЕсли;
КонецПроцедуры
Последний параметр Истина открывает диалог выбора папки. В файловой базе «сервер» — это компьютер пользователя, но схему с хранилищем лучше оставить: код не придётся переписывать при переходе на клиент-сервер.
Чтобы дописать строки в уже существующий файл, используйте ОткрытьФайл() вместо СоздатьФайл(), затем те же Добавить() и Записать().
COM-объект ADODB и SQL-запросы для записи DBF
Через COM можно работать с DBF как с базой данных: создать таблицу командой CREATE TABLE и залить строки INSERT. Способ нужен, когда приёмник ждёт таблицу Visual FoxPro или когда логику проще описать на SQL.
Пример на провайдере Microsoft ACE, он есть в 32- и 64-разрядном исполнении:
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Export\;Extended Properties=dBASE IV;");
Соединение.Execute("CREATE TABLE payments (CODE CHAR(20), NAME CHAR(100), SUMMA DOUBLE, DOCDATE DATE)");
Наименование = СтрЗаменить("ООО ""Ромашка""", "'", "''");
Соединение.Execute("INSERT INTO payments (CODE, NAME, SUMMA, DOCDATE) VALUES ('0001', '"
+ Наименование + "', 1500.50, #10/07/2026#)");
Соединение.Close();
Что здесь важно:
Data Source— это папка, а не файл. Имя таблицы становится именем файла:payments.dbf.- Имя таблицы держите в пределах 8 символов: драйвер dBASE рассчитан на короткие имена файлов.
- Дата в литерале
#...#пишется в американском порядке: месяц/день/год. - Апострофы в строках удваивайте, иначе SQL-команда сломается на первом же «ООО О’Нил».
Для таблиц FoxPro используют провайдер VFPOLEDB.1 и синтаксис FoxPro:
CREATE TABLE payments FREE (CODE C(20), NAME C(100), SUMMA N(15,2), DOCDATE D)
Здесь длину и точность числа задаёте вы сами, как в XBase. Но провайдер VFP существует только в 32-разрядном варианте.
COM-объект создаётся там, где выполняется код. В клиент-серверной базе код на сервере ищет провайдер на сервере 1С, а он почти всегда 64-разрядный. Провайдер, установленный на компьютере бухгалтера, серверу не поможет.
Кодировку символов провайдер берёт из своих настроек и системы, управлять ей сложнее, чем в XBase. Если кириллица важна, проверьте результат на стороне приёмника до того, как ставить выгрузку в работу.
Внешняя обработка и готовые библиотеки выгрузки
Когда выгрузка повторяется, код из примера выше переносят во внешнюю обработку (.epf). Конфигурацию трогать не нужно, обновления типовой базы не ломаются.
Порядок такой:
- В конфигураторе создайте внешнюю обработку, добавьте форму и команду
Выгрузить. - Вставьте серверную функцию и клиентскую процедуру из раздела про
XBase. - Вынесите на форму реквизиты: период, организацию, имя файла.
- Для разового запуска откройте обработку через главное меню:
Файл → Открыть. - Для постоянной работы подключите её в
Администрирование → Печатные формы, отчеты и обработки → Дополнительные отчеты и обработки.
Для открытия внешних обработок у пользователя должно быть право на их интерактивное открытие. Без него пункт Файл → Открыть выдаст ошибку прав.
Практики делают в такой обработке универсальную функцию, которая принимает таблицу значений и сама описывает поля по типам колонок:
| Тип колонки в 1С | Поле DBF | Длина и точность |
|---|---|---|
| Строка длиной N | S | N; неограниченную строку обрезают до 254 |
| Число (разрядность P, дробная часть F) | N | P + 2 при F > 0, P + 1 при F = 0; точность F |
| Дата | D | 8 |
| Булево | L | 1 |
| Ссылка | S | наименование или код строкой |
Сведения о типе берут из Колонка.ТипЗначения: квалификаторы КвалификаторыСтроки.Длина и КвалификаторыЧисла.Разрядность. Имена полей задают отдельным соответствием «колонка → поле», потому что имена колонок обычно русские и длиннее 10 символов.
Готовые обработки «Выгрузка в DBF» легко найти в сети. Перед запуском откройте модуль и посмотрите код: внешняя обработка выполняется с вашими правами и может изменить данные базы.
Прямая запись байтов: собираем DBF вручную
Иногда приёмник отвергает файл из-за мелочи в заголовке: не та сигнатура, нулевой байт кодовой страницы. Тогда файл собирают сами через ЗаписьДанных (платформа 8.3.9 и новее).
Структура файла dBASE III:
| Блок | Размер | Содержимое |
|---|---|---|
| Заголовок | 32 байта | сигнатура 0x03, дата правки (год − 1900, месяц, день), число записей, длина заголовка, длина записи, байт 29 — кодовая страница |
| Описание полей | 32 байта на поле | имя (11 байт), тип, длина, точность |
| Конец заголовка | 1 байт | 0x0D |
| Записи | длина записи × число записей | флаг удаления (пробел) + значения полей |
| Конец файла | 1 байт | 0x1A |
Длина заголовка = 32 + 32 × число полей + 1. Длина записи = 1 + сумма длин полей. Для трёх полей длиной 20, 15 и 8 получится заголовок 129 байт и запись 44 байта.
&НаСервере
Процедура ЗаписатьDBFПобайтно(ИмяФайла, Таблица)
// Таблица: колонки Код (Строка), Сумма (Число), Дата (Дата)
Поля = Новый Массив;
Поля.Добавить(Новый Структура("Имя, Тип, Длина, Точность, Колонка", "CODE", "C", 20, 0, "Код"));
Поля.Добавить(Новый Структура("Имя, Тип, Длина, Точность, Колонка", "SUMMA", "N", 15, 2, "Сумма"));
Поля.Добавить(Новый Структура("Имя, Тип, Длина, Точность, Колонка", "DOCDATE", "D", 8, 0, "Дата"));
ДлинаЗаписи = 1;
Для Каждого Поле Из Поля Цикл
ДлинаЗаписи = ДлинаЗаписи + Поле.Длина;
КонецЦикла;
ДлинаЗаголовка = 32 + 32 * Поля.Количество() + 1;
Сегодня = ТекущаяДатаСеанса();
Запись = Новый ЗаписьДанных(ИмяФайла); // порядок байтов по умолчанию LittleEndian
// Заголовок, 32 байта
Запись.ЗаписатьБайт(3);
Запись.ЗаписатьБайт(Год(Сегодня) - 1900);
Запись.ЗаписатьБайт(Месяц(Сегодня));
Запись.ЗаписатьБайт(День(Сегодня));
Запись.ЗаписатьЦелое32(Таблица.Количество());
Запись.ЗаписатьЦелое16(ДлинаЗаголовка);
Запись.ЗаписатьЦелое16(ДлинаЗаписи);
ЗаписатьНули(Запись, 17);
Запись.ЗаписатьБайт(101); // 0x65 — кодовая страница 866
ЗаписатьНули(Запись, 2);
// Описания полей, по 32 байта
Для Каждого Поле Из Поля Цикл
Запись.ЗаписатьСимволы(Поле.Имя, "cp866");
ЗаписатьНули(Запись, 11 - СтрДлина(Поле.Имя));
Запись.ЗаписатьСимволы(Поле.Тип, "cp866");
ЗаписатьНули(Запись, 4);
Запись.ЗаписатьБайт(Поле.Длина);
Запись.ЗаписатьБайт(Поле.Точность);
ЗаписатьНули(Запись, 14);
КонецЦикла;
Запись.ЗаписатьБайт(13);
// Записи
Для Каждого Строка Из Таблица Цикл
Запись.ЗаписатьСимволы(" ", "cp866");
Для Каждого Поле Из Поля Цикл
Значение = Строка[Поле.Колонка];
Если Поле.Тип = "C" Тогда
Текст = Лев(Значение, Поле.Длина);
Текст = Текст + Пробелы(Поле.Длина - СтрДлина(Текст));
ИначеЕсли Поле.Тип = "N" Тогда
Текст = Формат(Значение, СтрШаблон("ЧДЦ=%1; ЧРД=.; ЧГ=0; ЧН=0", Поле.Точность));
Если СтрДлина(Текст) > Поле.Длина Тогда
ВызватьИсключение "Число не помещается в поле " + Поле.Имя;
КонецЕсли;
Текст = Пробелы(Поле.Длина - СтрДлина(Текст)) + Текст;
Иначе // D
Текст = ?(ЗначениеЗаполнено(Значение), Формат(Значение, "ДФ=yyyyMMdd"), Пробелы(8));
КонецЕсли;
Запись.ЗаписатьСимволы(Текст, "cp866");
КонецЦикла;
КонецЦикла;
Запись.ЗаписатьБайт(26);
Запись.Закрыть();
КонецПроцедуры
&НаСервере
Процедура ЗаписатьНули(Запись, Количество)
Для Сч = 1 По Количество Цикл
Запись.ЗаписатьБайт(0);
КонецЦикла;
КонецПроцедуры
&НаСервере
Функция Пробелы(Количество)
Результат = "";
Для Сч = 1 По Количество Цикл
Результат = Результат + " ";
КонецЦикла;
Возврат Результат;
КонецФункции
Обратите внимание на тип строки: в самом файле строковое поле обозначается буквой C, а S — это обозначение только для объекта XBase.
Число записей в заголовке должно совпадать с фактическим. Если вы пропускаете строки по условию, сначала отфильтруйте таблицу, потом пишите.
Кодировка и кириллица в DBF
Кракозябры — самая частая жалоба на выгрузку. Причина почти всегда в несовпадении кодовых страниц.
| Вариант | Кодовая страница | Байт 29 | Кто обычно ждёт |
|---|---|---|---|
КодировкаXBase.OEM | 866 (DOS) | 0x65 или 0x26 | FoxPro, Clipper, большинство банковских форматов |
КодировкаXBase.ANSI | 1251 (Windows) | 0xC9 | программы под Windows, ГИС, Excel |
Как действовать:
- Спросите у получателя кодировку прямо. Формат реестра обычно её указывает.
- Задайте
ДБФ.Кодировкадо вызоваСоздатьФайл(). - Если приёмник читает кодовую страницу из байта 29 и показывает мусор, откройте файл в HEX-редакторе и сверьте этот байт с таблицей.
Символов «ёлочек», длинного тире и знака евро в 866-й странице нет. Перед записью замените их: СтрЗаменить(Текст, "«", """"). Буква «ё» и знак «№» в 866-й есть.
Ещё одна ловушка — длина. В DBF длина строкового поля считается в байтах, а 866 и 1251 однобайтовые, поэтому 100 символов = 100 байт. Длинное наименование обрезайте через Лев() сами, чтобы видеть, где именно срезано.
Автоматическая выгрузка в DBF по расписанию
Есть два рабочих варианта без правки типовой конфигурации.
Регламентное задание в расширении. В расширении создайте общий модуль с процедурой выгрузки и регламентное задание, которое её вызывает. Файл пишется в сетевую папку, доступную службе сервера 1С. В файловой базе регламентные задания выполняются только при открытом сеансе, поэтому для неё надёжнее второй вариант.
Планировщик Windows и параметр /Execute. Внешняя обработка открывается сразу после запуска 1С, выгружает файл и закрывает программу:
"C:\Program Files\1cv8\common\1cestart.exe" ENTERPRISE /F"D:\Bases\Buh" /N"Выгрузка" /P"пароль" /Execute"D:\Scripts\export_dbf.epf"
В модуле формы обработки вызовите серверную выгрузку в ПриОткрытии, затем ЗавершитьРаботуСистемы(Ложь). Для такого запуска заведите отдельного пользователя с минимальными правами: пароль лежит в задании планировщика открытым текстом.
Добавляйте в имя файла дату: reestr_20261007.dbf. Так вчерашний реестр не перезапишется сегодняшним, если получатель ещё не забрал файл.