При программной выгрузке отчетов и печатных форм из 1С в форматы PDF, XLS или XLSX разработчики часто сталкиваются с ситуацией, когда итоговый файл сохраняется поврежденным. Например, файл с расширением .pdf не открывается в программах просмотра, файл .xls выдает предупреждение о несовпадении формата при открытии в Microsoft Excel, и лишь один из форматов выгружается корректно. При этом интерактивное сохранение через стандартное меню «Файл — Сохранить как» работает без нареканий.
Разберем детально, почему возникает такое поведение платформы «1С:Предприятие 8.3», и рассмотрим правильные варианты реализации программного сохранения.
Выясним причину, по которой метод Записать() объекта ТабличныйДокумент создает поврежденные файлы:
0, 1, 2) или строка. Если передать такое значение во второй параметр метода Записать(ИмяФайла, ТипФайлаТабличногоДокумента), платформа не вызывает исключение, а молча применяет формат по умолчанию (MXL или HTML). В результате формируется файл с содержимым HTML/MXL, но с расширением .pdf, который программы чтения PDF считать не могут.Записать() не добавляет расширение к имени файла автоматически, даже если передан корректный тип документа. Расширение обязательно должно присутствовать в переданной строке полного пути.Вывод = ИспользованиеВывода.Запретить, сохранение в сторонние форматы может завершаться созданием пустого документа.Посмотрим на классический пример заполнения табличного документа по макету и его прямого сохранения в формат PDF на сервере с явным указанием системного типа ТипФайлаТабличногоДокумента.PDF:
&НаСервере
Процедура СформироватьИСохранитьТабличныйДокумент()
Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Валюты.Ссылка КАК Ссылка,
| Валюты.Представление КАК Представление
|ИЗ
| Справочник.Валюты КАК Валюты";
РезультатЗапроса = Запрос.Выполнить();
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ОбластьДетальныхЗаписей = Макет.ПолучитьОбласть("Детали");
ОбластьПодвалТаблицы = Макет.ПолучитьОбласть("ПодвалТаблицы");
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
ТабДок = Новый ТабличныйДокумент;
ТабДок.Очистить();
ТабДок.Вывод = ИспользованиеВывода.Разрешить;
ТабДок.Вывести(ОбластьЗаголовок);
ТабДок.Вывести(ОбластьШапкаТаблицы);
ТабДок.НачатьАвтогруппировкуСтрок();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетальныеЗаписи);
ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетальныеЗаписи.Уровень());
КонецЦикла;
ТабДок.ЗакончитьАвтогруппировкуСтрок();
ТабДок.Вывести(ОбластьПодвалТаблицы);
ТабДок.Вывести(ОбластьПодвал);
// Явное указание пути с расширением и типа файла
ТабДок.Записать("E:\Export\Report.pdf", ТипФайлаТабличногоДокумента.PDF);
КонецПроцедуры
Рассмотрим подробнее, как правильно организовать выгрузку, если пользователь выбирает формат на форме через переключатель или список выбора. Необходимо явно сопоставить выбранный вариант со значением системного перечисления ТипФайлаТабличногоДокумента и дополнить путь к файлу нужным расширением:
&НаСервере
Процедура СохранитьТабДокВВыбранномФормате(ТабличныйДокументНаСервере, КаталогСохранения, БазовоеИмяФайла, ВариантВыбора)
ТипФайла = Неопределено;
Расширение = "";
Если ВариантВыбора = 0 Тогда
ТипФайла = ТипФайлаТабличногоДокумента.PDF;
Расширение = ".pdf";
ИначеЕсли ВариантВыбора = 1 Тогда
ТипФайла = ТипФайлаТабличногоДокумента.XLSX;
Расширение = ".xlsx";
ИначеЕсли ВариантВыбора = 2 Тогда
ТипФайла = ТипФайлаТабличногоДокумента.XLS;
Расширение = ".xls";
Иначе
ВызватьИсключение "Указан неподдерживаемый формат файла для выгрузки.";
КонецЕсли;
ТабличныйДокументНаСервере.Вывод = ИспользованиеВывода.Разрешить;
ПолныйПуть = КаталогСохранения + "\" + БазовоеИмяФайла + Расширение;
ТабличныйДокументНаСервере.Записать(ПолныйПуть, ТипФайла);
КонецПроцедуры
Разберем по шагам задачу сохранения файла на компьютере пользователя в клиент-серверной архитектуре. Метод Записать() на сервере обращается к файловой системе сервера, поэтому для передачи файла на клиентскую машину формируем временный файл, помещаем его во временное хранилище и выгружаем на клиент:
&НаСервере
Функция СформироватьФайлВоВременномХранилище(ТабДок, ФорматВыгрузки)
ТипФайла = ТипФайлаТабличногоДокумента.PDF;
Расширение = "pdf";
Если ФорматВыгрузки = "XLSX" Тогда
ТипФайла = ТипФайлаТабличногоДокумента.XLSX;
Расширение = "xlsx";
ИначеЕсли ФорматВыгрузки = "XLS" Тогда
ТипФайла = ТипФайлаТабличногоДокумента.XLS;
Расширение = "xls";
КонецЕсли;
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(Расширение);
ТабДок.Вывод = ИспользованиеВывода.Разрешить;
ТабДок.Записать(ИмяВременногоФайла, ТипФайла);
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяВременногоФайла);
УдалитьФайлы(ИмяВременногоФайла);
Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификатор);
КонецФункции
&НаКлиенте
Процедура СохранитьНаКлиенте(Команда)
// Получаем адрес файла во временном хранилище
АдресХранилища = СформироватьФайлВоВременномХранилище(Элементы.ПолеТабличногоДокумента, "PDF");
ПараметрыДиалога = Новый ПараметрыДиалогаПолученияФайлов("Сохранить отчет", "Отчет.pdf");
ПолучитьФайлССервера(АдресХранилища, "Отчет.pdf", ПараметрыДиалога);
КонецПроцедуры
ТипФайлаТабличногоДокумента.XLS95 не поддерживается при выполнении кода на стороне сервера и в веб-клиенте. Всегда используйте ТипФайлаТабличногоДокумента.XLS или более современный ТипФайлаТабличногоДокумента.XLSX.WMF, EMF). Если в документе используются логотипы или изображения, они должны быть в форматах PNG или JPG.