Как выгрузить данные документа в файл DBF на управляемых формах 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

При переходе с обычных форм на управляемые разработчики часто сталкиваются с ошибками при попытке сформировать файл DBF. Типичная ситуация: на клиенте создается объект XBase, затем вызывается серверная функция для получения строк документа, и разработчик пытается вернуть результат запроса или объект ТаблицаЗначений напрямую в клиентский контекст. В результате платформа выдает исключение: «Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа. Ошибка преобразования данных XDTO...».

Разберем причины возникновения этой ошибки, выясним, почему не стоит передавать выборку через реквизиты формы, и рассмотрим архитектурно правильный шаблон выгрузки данных документа в формат DBF.

Анализ проблемы: почему возникает ошибка передачи данных

Посмотрим на частую ошибку в кодовой базе. Разработчик пытается выполнить запрос на сервере и вернуть таблицу значений клиенту:


&НаКлиенте
Процедура СоздатьФайл(Команда)
    // ... создание XBase ...
    Выборка = ДанныеДокумента(Объект.Реализация); // Ошибка вызова контекста!
    // ... запись в файл ...
КонецПроцедуры

&НаСервереБезКонтекста
Функция ДанныеДокумента(Ссылка)
    Запрос = Новый Запрос;
    // ... текст запроса ...
    Возврат Запрос.Выполнить().Выгрузить(); // Возвращается ТаблицаЗначений
КонецФункции

Выясним причину ошибки: тип данных ТаблицаЗначений не сериализуется для передачи на тонкий клиент. Тонкий клиент попросту не поддерживает работу с таблицами значений в оперативной памяти. Попытка обойти это через создание реквизита формы типа ТаблицаЗначений и метод ЗначениеВРеквизитФормы() формально решает проблему передачи, но является грубой архитектурной ошибкой. Загрузка сотен или тысяч строк в контекст формы резко раздувает ее размер, перегружает канал связи между клиентом и сервером и замедляет работу интерфейса.

Правильный паттерн выгрузки: полная обработка на сервере

Рассмотрим эталонную схему клиент-серверного взаимодействия для формирования файлов выгрузки:

  1. На стороне клиента пользователь инициирует команду (нажатие кнопки) и передает ссылку на документ на сервер.
  2. На сервере в контексте &НаСервереБезКонтекста создается временный файл через ПолучитьИмяВременногоФайла().
  3. Здесь же, на сервере, создается и заполняется объект XBase, после чего файл обязательно закрывается методом ЗакрытьФайл().
  4. Сформированный файл считывается в объект ДвоичныеДанные и помещается во временное хранилище через ПоместитьВоВременноеХранилище().
  5. Адрес во временном хранилище возвращается на клиент, где файл сохраняется на диск пользователя или интерактивно через диалог.

Разберем по шагам реализацию этой схемы на примере выгрузки табличной части документа Реализация товаров и услуг.

Пример реализации выгрузки в DBF через временное хранилище

Посмотрим на практический пример программного кода для модуля управляемой формы:


&НаКлиенте
Процедура ВыгрузитьВDBF(Команда)
    
    Если Не ЗначениеЗаполнено(Объект.Ссылка) Тогда
        Предупреждение("Сначала необходимо записать документ!");
        Возврат;
    КонецЕсли;
    
    // Формируем файл на сервере и получаем адрес во временном хранилище
    АдресФайла = СформироватьDBFНаСервере(Объект.Ссылка);
    
    // Получаем файл из временного хранилища и сохраняем на клиенте
    ИмяФайла = "Export_" + СокрЛП(Объект.Номер) + ".dbf";
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
    Диалог.ПолноеИмяФайла = ИмяФайла;
    Диалог.Фильтр = "Файлы dBase (*.dbf)|*.dbf";
    
    Если Диалог.Выбрать() Тогда
        ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресФайла);
        ДвоичныеДанныеФайла.Записать(Диалог.ПолноеИмяФайла);
        ПоказатьОповещениеПользователя("Выгрузка завершена", , "Файл сохранен: " + Диалог.ПолноеИмяФайла);
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция СформироватьDBFНаСервере(СсылкаНаДокумент)
    
    // 1. Получаем путь к временному файлу на стороне сервера
    ВременныйПуть = ПолучитьИмяВременногоФайла("dbf");
    
    // 2. Инициализируем XBase и настраиваем поля таблицы
    ФайлDBF = Новый XBase;
    ФайлDBF.Кодировка = КодировкаXBase.OEM; // Либо КодировкаXBase.ANSI
    
    // Внимание: имя поля в DBF не должно превышать 10 символов
    ФайлDBF.Поля.Добавить("NOMER", "N", 5, 0);
    ФайлDBF.Поля.Добавить("NAIMEN", "S", 80, 0);
    ФайлDBF.Поля.Добавить("KOLVO", "N", 15, 3);
    ФайлDBF.Поля.Добавить("CENA", "N", 15, 2);
    ФайлDBF.Поля.Добавить("SUMMA", "N", 15, 2);
    
    ФайлDBF.СоздатьФайл(ВременныйПуть);
    
    // 3. Выполняем выборку данных документа
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ТабЧасть.НомерСтроки КАК НомерСтроки,
        |	ТабЧасть.Номенклатура.Наименование КАК НоменклатураНаименование,
        |	ТабЧасть.Количество КАК Количество,
        |	ТабЧасть.Цена КАК Цена,
        |	ТабЧасть.Сумма КАК Сумма
        |ИЗ
        |	Документ.РеализацияТоваровУслуг.Товары КАК ТабЧасть
        |ГДЕ
        |	ТабЧасть.Ссылка = &Ссылка
        |УПОРЯДОЧИТЬ ПО
        |	НомерСтроки";
        
    Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
    Выборка = Запрос.Выполнить().Выбрать();
    
    // 4. Заполняем таблицу DBF строками
    Пока Выборка.Следующий() Цикл
        ФайлDBF.Добавить();
        ФайлDBF.NOMER = Выборка.НомерСтроки;
        ФайлDBF.NAIMEN = Строка(Выборка.НоменклатураНаименование);
        ФайлDBF.KOLVO = Выборка.Количество;
        ФайлDBF.CENA = Выборка.Цена;
        ФайлDBF.SUMMA = Выборка.Сумма;
        ФайлDBF.Записать();
    КонецЦикла;
    
    // 5. Обязательно закрываем файл для снятия блокировки ОС
    ФайлDBF.ЗакрытьФайл();
    
    // 6. Помещаем файл во временное хранилище и удаляем файл на диске сервера
    ФайлВПамяти = Новый ДвоичныеДанные(ВременныйПуть);
    АдресВХранилище = ПоместитьВоВременноеХранилище(ФайлВПамяти);
    
    УдалитьФайлы(ВременныйПуть);
    
    Возврат АдресВХранилище;
    
КонецФункции

Тонкости и важные правила при работе с объектом XBase

Рассмотрим подробнее важные технические нюансы, несоблюдение которых приводит к ошибкам выполнения:

  1. Обязательный вызов метода ЗакрытьФайл(): пока файл не закрыт явно, дескриптор файла удерживается платформой 1С. Попытка прочитать файл через Новый ДвоичныеДанные(ВременныйПуть) вызовет исключение совместного доступа к файлу.
  2. Длина имени полей: структура формата DBF (dBase III / IV) накладывает жесткое ограничение — имя поля не может превышать 10 символов, должно содержать только латиницу, цифры и символ подчеркивания. Попытка задать поле "НОМЕНКЛАТУРА" или имя длиннее 10 знаков приведет к ошибке при создании структуры файла.
  3. Типизация полей: строковые поля типа "S" требуют явного строкового значения. Передача ссылочного типа (например, СправочникСсылка.Номенклатура) вызовет ошибку заполнения. В запросе следует сразу обращаться к реквизитам через точку (Номенклатура.Наименование) или использовать функцию Строка().
  4. Кодировка данных: объект XBase не поддерживает кодировку UTF-8. Доступны только два режима: КодировкаXBase.OEM (кодовая страница CP866, стандарт для DOS-систем) и КодировкаXBase.ANSI (Windows-1251).
  5. Локальные пути к файлам: никогда не используйте прямые жестко прописанные пути (например, "D:\dBase.dbf") внутри серверных процедур. Сервер 1С выполняется под отдельным системным пользователем, который может не иметь прав на запись в корень диска, либо сервер может функционировать под управлением Linux, где структура путей принципиально иная. Всегда используйте метод ПолучитьИмяВременногоФайла().
← На главную