При переходе с толстого или тонкого клиента на веб-клиент разработчики часто сталкиваются с проблемами при работе с файлами. Типичная задача — сформировать печатную форму в формате PDF и прикрепить ее к документу информационной базы. Однако привычные методы сохранения на локальный диск и вызовы синхронных функций в веб-клиенте вызывают ошибки или не дают результата. Разберем причины такого поведения и рассмотрим правильные варианты реализации данной задачи.
Проанализируем основные ограничения, с которыми сталкивается разработчик в веб-клиенте:
C:\temp\ из кода клиента невозможен.КаталогВременныхФайлов() и ПолучитьИмяВременногоФайла() не поддерживаются в контексте клиента веб-клиента.ПоместитьФайлы в веб-клиенте вызовет исключение.Разберем по шагам правильную архитектуру решения. Так как табличный документ формируется на сервере и файл должен быть записан в базу данных, весь процесс должен происходить в серверном контексте без участия клиентской файловой системы.
Рассмотрим типовой алгоритм работы через временный файл на стороне сервера:
ТабличныйДокумент в серверной процедуре.ПолучитьИмяВременногоФайла("pdf").ДвоичныеДанные.ХранилищеЗначения или создаем новый элемент справочника присоединенных файлов.Посмотрим на пример серверного кода:
&НаСервере
Процедура СформироватьИПрикрепитьPDFКДокументу(СсылкаНаДокумент)
// 1. Формируем табличный документ (печатную форму)
ТабДок = Новый ТабличныйДокумент;
// ... заполнение ТабДок данными ...
// 2. Получаем временное имя файла на сервере
ВременныйФайл = ПолучитьИмяВременногоФайла("pdf");
Попытка
// 3. Записываем табличный документ в формате PDF
ТабДок.Записать(ВременныйФайл, ТипФайлаТабличногоДокумента.PDF);
// 4. Получаем двоичные данные файла
ДанныеФайла = Новый ДвоичныеДанные(ВременныйФайл);
// 5. Записываем данные в реквизит объекта или создаем присоединенный файл
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокументОбъект.ХранилищеПечатнойФормы = Новый ХранилищеЗначения(ДанныеФайла, Новый СжатиеДанных(9));
ДокументОбъект.Записать();
Исключение
// В случае ошибки обязательно очищаем временный файл и передаем исключение
УдалитьФайлы(ВременныйФайл);
ВызватьИсключение;
КонецПопытки;
// 6. Удаляем временный файл с диска сервера
УдалитьФайлы(ВременныйФайл);
КонецПроцедуры
В современных версиях платформы 1С:Предприятие 8.3 можно избежать создания физических файлов на диске сервера. Рассмотрим более быстрый и надежный способ — запись табличного документа напрямую в поток в оперативной памяти.
Посмотрим на пример реализации с использованием объекта ПотокВПамяти:
&НаСервере
Процедура СформироватьИСохранитьВПамяти(СсылкаНаДокумент)
ТабДок = Новый ТабличныйДокумент;
// ... заполнение ТабДок данными ...
// Создаем поток в оперативной памяти
Поток = Новый ПотокВПамяти;
// Записываем PDF напрямую в поток
ТабДок.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
// Получаем двоичные данные и закрываем поток
ДанныеФайла = Поток.ЗакрытьИПолучитьДвоичныеДанные();
// Прикрепляем файл к объекту базы данных
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокументОбъект.ХранилищеПечатнойФормы = Новый ХранилищеЗначения(ДанныеФайла, Новый СжатиеДанных(9));
ДокументОбъект.Записать();
КонецПроцедуры
Выясним несколько важных моментов, на которые следует обратить внимание при настройке серверной среды:
ТабличныйДокумент в системе должны быть установлены графическая библиотека libgdiplus и базовые шрифты TrueType (например, пакет msttcorefonts). Без них вызов метода Записать завершится ошибкой.ПоместитьВоВременноеХранилище, а на клиенте вызывается асинхронный метод НачатьПолучениеФайлаССервера.