При разработке внешних отчетов и обработок разработчики часто сталкиваются с необходимостью получить двоичные данные (исходный файл .erf или .epf) прямо во время выполнения кода самого отчета. Если файл открывается стандартно через меню Файл — Открыть, то в свойстве ИспользуемоеИмяФайла объекта содержится физический путь к файлу на диске. В этом случае получить двоичные данные легко вызовом Новый ДвоичныеДанные(ИспользуемоеИмяФайла).
Однако если отчет подключен как внешний через подсистему БСП (Библиотека Стандартных Подсистем) или аналогичный справочник дополнительных отчетов и обработок, то в свойстве ИспользуемоеИмяФайла оказывается навигационная ссылка вида e1cib/tempstorage/.... При попытке выгрузить данные из этой ссылки возникает ошибка файловой операции или ошибка считывания из временного хранилища. Проанализируем, почему так происходит, и рассмотрим проверенные варианты решения этой задачи.
Рассмотрим, что происходит на стороне платформы при подключении внешнего отчета:
ВнешниеОтчеты.Подключить() или ВнешниеОбработки.Подключить() считывает двоичные данные из базы данных или временного хранилища и регистрирует их в оперативной памяти сервера как динамический объект метаданных.e1cib/tempstorage/... является лишь внутренним адресом сеансового хранилища, используемым платформой в момент подключения.Новый ДвоичныеДанные() принимает на вход исключительно реальный физический путь к файлу в файловой системе ОС. Передача навигационной ссылки платформы в данный конструктор всегда приводит к ошибке «Неправильный путь к файлу».ПолучитьИзВременногоХранилища() по старой строке-ссылке возвращает Неопределено или ошибку доступа.Разберем основные способы, с помощью которых можно обойти это ограничение платформы.
Если внешний отчет или обработка зарегистрированы в справочнике ДополнительныеОтчетыИОбработки, то исходные двоичные данные файла хранятся в реквизите типа ХранилищеЗначения этого справочника. Нам достаточно определить, из какого элемента справочника была запущена обработка.
Для этого извлечем имя подключенного объекта из служебного свойства формы ИмяФормы и найдем соответствующий элемент в справочнике:
&НаСервере
Функция ПолучитьДвоичныеДанныеТекущегоОтчета()
// Имя формы подключенной внешней обработки имеет вид:
// "ВнешняяОбработка.ИмяПодключеннойОбработки.Форма.ФормаОтчета"
СтрокаИмени = СтрЗаменить(ИмяФормы, ".", Символы.ПС);
ИмяОбъекта = СтрПолучитьСтроку(СтрокаИмени, 2);
// Ищем элемент в справочнике ДополнительныеОтчетыИОбработки
СсылкаНаДопОбработку = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоРеквизиту("ИмяОбъекта", ИмяОбъекта);
Если ЗначениеЗаполнено(СсылкаНаДопОбработку) Тогда
// Извлекаем двоичные данные из хранилища значений справочника
ДвоичныеДанныеОтчета = СсылкаНаДопОбработку.ХранилищеОбработки.Получить();
Возврат ДвоичныеДанныеОтчета;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Важный момент: данный способ идеально подходит для конфигураций с БСП или подсистемами, использующими стандартные механизмы регистраций дополнительных отчетов и обработок.
Если вы дорабатываете механизм подключения внешних отчетов в конфигурации, то наиболее правильным решением будет сохранение двоичных данных во временное хранилище с привязкой к уникальному идентификатору создаваемой формы.
Посмотрим на пример кода в модуле, который открывает форму отчета:
// Код подсистемы перед открытием формы внешнего отчета
&НаСервере
Функция ПодготовитьПараметрыОткрытия(СсылкаНаДопОбработку, ИдентификаторФормы)
ПараметрыОткрытия = Новый Структура;
// Получаем двоичные данные из справочника
ДвоичныеДанные = СсылкаНаДопОбработку.ХранилищеОбработки.Получить();
// Помещаем во временное хранилище с указанием УникальногоИдентификатора формы
// Это гарантирует, что хранилище живет всё время работы формы
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанные, ИдентификаторФормы);
ПараметрыОткрытия.Вставить("АдресДвоичныхДанных", АдресХранилища);
Возврат ПараметрыОткрытия;
КонецФункции
Далее в модуле формы самого внешнего отчета мы можем легко считать данные в обработчике ПриСозданииНаСервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("АдресДвоичныхДанных") И ЗначениеЗаполнено(Параметры.АдресДвоичныхДанных) Тогда
ДвоичныеДанныеОтчета = ПолучитьИзВременногоХранилища(Параметры.АдресДвоичныхДанных);
// Используем полученные двоичные данные
КонецЕсли;
КонецПроцедура
Часто двоичные данные внешнего отчета требуются для извлечения служебных файлов, макетов, библиотек или поставки связанных внешних компонентов. Если цель состоит в том, чтобы отчет нес в себе необходимые файлы независимо от способа его запуска (будь то диск или справочник доп. обработок), проанализируем решение с добавлением макета.
Теперь из кода формы или объекта отчета мы можем извлечь эти данные в любой момент, независимо от значения ИспользуемоеИмяФайла:
&НаСервере
Процедура ИзвлечьДанныеИзМакета()
// Получаем объект внешней обработки из реквизита формы "Отчет" или "Объект"
ОбъектОбработки = РеквизитФормыВЗначение("Отчет");
// Считываем двоичные данные из встроенного макета
ДвоичныеДанныеМакета = ОбъектОбработки.ПолучитьМакет("ХранилищеОписаний");
Если ДвоичныеДанныеМакета <> Неопределено Тогда
ПутьКФайлу = ПолучитьИмяВременногоФайла(".tmp");
ДвоичныеДанныеМакета.Записать(ПутьКФайлу);
// Выполняем нужные операции с файлом на диске
// Обязательно подчищаем временный файл за собой
УдалитьФайлы(ПутьКФайлу);
КонецЕсли;
КонецПроцедура
Прямое считывание двоичных данных через ИспользуемоеИмяФайла работает только при запуске файла с локального или сетевого диска. Для отчетов, подключенных через справочники базы данных, следует применять выборку из справочника ДополнительныеОтчетыИОбработки по имени формы, передавать длительный адрес временного хранилища через параметры формы или хранить служебные данные во внутренних макетах с типом Двоичные данные.