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