Почему метод Записать() некорректно сохраняет табличный документ в PDF и Excel и как это исправить?

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

При программной выгрузке отчетов и печатных форм из 1С в форматы PDF, XLS или XLSX разработчики часто сталкиваются с ситуацией, когда итоговый файл сохраняется поврежденным. Например, файл с расширением .pdf не открывается в программах просмотра, файл .xls выдает предупреждение о несовпадении формата при открытии в Microsoft Excel, и лишь один из форматов выгружается корректно. При этом интерактивное сохранение через стандартное меню «Файл — Сохранить как» работает без нареканий.

Разберем детально, почему возникает такое поведение платформы «1С:Предприятие 8.3», и рассмотрим правильные варианты реализации программного сохранения.

Анализ причин некорректного сохранения

Выясним причину, по которой метод Записать() объекта ТабличныйДокумент создает поврежденные файлы:

  1. Передача числового индекса или строки вместо системного перечисления. Когда на управляемой форме организуется выбор формата (например, через переключатель, тумблер или выпадающий список), значением реквизита формы часто является число (0, 1, 2) или строка. Если передать такое значение во второй параметр метода Записать(ИмяФайла, ТипФайлаТабличногоДокумента), платформа не вызывает исключение, а молча применяет формат по умолчанию (MXL или HTML). В результате формируется файл с содержимым HTML/MXL, но с расширением .pdf, который программы чтения PDF считать не могут.
  2. Отсутствие автоматической подстановки расширения. Метод Записать() не добавляет расширение к имени файла автоматически, даже если передан корректный тип документа. Расширение обязательно должно присутствовать в переданной строке полного пути.
  3. Ограничения прав на вывод. Если у табличного документа программно или в свойствах макета установлено свойство Вывод = ИспользованиеВывода.Запретить, сохранение в сторонние форматы может завершаться созданием пустого документа.

Способ 1. Корректное программное формирование и экспорт табличного документа

Посмотрим на классический пример заполнения табличного документа по макету и его прямого сохранения в формат PDF на сервере с явным указанием системного типа ТипФайлаТабличногоДокумента.PDF:


&НаСервере
Процедура СформироватьИСохранитьТабличныйДокумент()

    Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Валюты.Ссылка КАК Ссылка,
        |   Валюты.Представление КАК Представление
        |ИЗ
        |   Справочник.Валюты КАК Валюты";
        
    РезультатЗапроса = Запрос.Выполнить();
    
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
    ОбластьДетальныхЗаписей = Макет.ПолучитьОбласть("Детали");
    ОбластьПодвалТаблицы = Макет.ПолучитьОбласть("ПодвалТаблицы");
    ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
    
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.Очистить();
    ТабДок.Вывод = ИспользованиеВывода.Разрешить;
    
    ТабДок.Вывести(ОбластьЗаголовок);
    ТабДок.Вывести(ОбластьШапкаТаблицы);
    
    ТабДок.НачатьАвтогруппировкуСтрок();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетальныеЗаписи);
        ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетальныеЗаписи.Уровень());
    КонецЦикла;
    ТабДок.ЗакончитьАвтогруппировкуСтрок();
    
    ТабДок.Вывести(ОбластьПодвалТаблицы);
    ТабДок.Вывести(ОбластьПодвал);
    
    // Явное указание пути с расширением и типа файла
    ТабДок.Записать("E:\Export\Report.pdf", ТипФайлаТабличногоДокумента.PDF);

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

Способ 2. Обработка выбора формата из переключателя на форме

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


&НаСервере
Процедура СохранитьТабДокВВыбранномФормате(ТабличныйДокументНаСервере, КаталогСохранения, БазовоеИмяФайла, ВариантВыбора)

    ТипФайла = Неопределено;
    Расширение = "";
    
    Если ВариантВыбора = 0 Тогда
        ТипФайла = ТипФайлаТабличногоДокумента.PDF;
        Расширение = ".pdf";
    ИначеЕсли ВариантВыбора = 1 Тогда
        ТипФайла = ТипФайлаТабличногоДокумента.XLSX;
        Расширение = ".xlsx";
    ИначеЕсли ВариантВыбора = 2 Тогда
        ТипФайла = ТипФайлаТабличногоДокумента.XLS;
        Расширение = ".xls";
    Иначе
        ВызватьИсключение "Указан неподдерживаемый формат файла для выгрузки.";
    КонецЕсли;
    
    ТабличныйДокументНаСервере.Вывод = ИспользованиеВывода.Разрешить;
    
    ПолныйПуть = КаталогСохранения + "\" + БазовоеИмяФайла + Расширение;
    ТабличныйДокументНаСервере.Записать(ПолныйПуть, ТипФайла);

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

Способ 3. Сохранение файла на клиенте в управляемом приложении

Разберем по шагам задачу сохранения файла на компьютере пользователя в клиент-серверной архитектуре. Метод Записать() на сервере обращается к файловой системе сервера, поэтому для передачи файла на клиентскую машину формируем временный файл, помещаем его во временное хранилище и выгружаем на клиент:


&НаСервере
Функция СформироватьФайлВоВременномХранилище(ТабДок, ФорматВыгрузки)

    ТипФайла = ТипФайлаТабличногоДокумента.PDF;
    Расширение = "pdf";
    
    Если ФорматВыгрузки = "XLSX" Тогда
        ТипФайла = ТипФайлаТабличногоДокумента.XLSX;
        Расширение = "xlsx";
    ИначеЕсли ФорматВыгрузки = "XLS" Тогда
        ТипФайла = ТипФайлаТабличногоДокумента.XLS;
        Расширение = "xls";
    КонецЕсли;

    ИмяВременногоФайла = ПолучитьИмяВременногоФайла(Расширение);
    ТабДок.Вывод = ИспользованиеВывода.Разрешить;
    ТабДок.Записать(ИмяВременногоФайла, ТипФайла);
    
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяВременногоФайла);
    УдалитьФайлы(ИмяВременногоФайла);
    
    Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификатор);

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

&НаКлиенте
Процедура СохранитьНаКлиенте(Команда)

    // Получаем адрес файла во временном хранилище
    АдресХранилища = СформироватьФайлВоВременномХранилище(Элементы.ПолеТабличногоДокумента, "PDF");
    
    ПараметрыДиалога = Новый ПараметрыДиалогаПолученияФайлов("Сохранить отчет", "Отчет.pdf");
    ПолучитьФайлССервера(АдресХранилища, "Отчет.pdf", ПараметрыДиалога);

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

Важные особенности и ограничения

  1. Формат XLS95: Значение ТипФайлаТабличногоДокумента.XLS95 не поддерживается при выполнении кода на стороне сервера и в веб-клиенте. Всегда используйте ТипФайлаТабличногоДокумента.XLS или более современный ТипФайлаТабличногоДокумента.XLSX.
  2. Векторная графика в PDF: При сохранении табличного документа в PDF не поддерживаются метафайлы Windows (WMF, EMF). Если в документе используются логотипы или изображения, они должны быть в форматах PNG или JPG.
← На главную