Файлы через временное хранилище 1С: адрес, загрузка, выгрузка и HTTP

· 9 мин

Содержание

Адрес временного хранилища в 1С возвращает метод ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор) на сервере или НачатьПомещениеФайла(...) на клиенте. Это строка вида e1cib/tempstorage/..., которую передают между клиентом и сервером вместо самих двоичных данных. Достать данные обратно можно методом ПолучитьИзВременногоХранилища(Адрес).

Типичная боль разработчика: файл выбран на клиенте, а разобрать его нужно на сервере, или наоборот — сервер сформировал выгрузку, и её надо отдать пользователю. Тащить двоичные данные параметром через вызов сервера дорого и неудобно. Временное хранилище решает это одной строкой адреса. Ниже — рабочие примеры для загрузки, выгрузки, HTTP и фоновых заданий.

Как устроено временное хранилище и что такое его адрес

Временное хранилище — область памяти сеанса на стороне сервера 1С:Предприятия. В неё можно положить любое значение, которое умеет сериализоваться: двоичные данные файла, таблицу значений, структуру, строку.

Взамен платформа выдаёт адрес. Это обычная строка, поэтому её легко хранить в реквизите формы, передавать в серверные процедуры и в параметры фонового задания.

Что важно знать про адрес:

  • 🔑 Он привязан к сеансу. В другом сеансе (другой пользователь, HTTP-сервис, внешнее приложение) этот адрес ничего не откроет.
  • ⏳ У значения есть время жизни. Если при помещении указать уникальный идентификатор формы, данные живут, пока открыта эта форма. Без идентификатора значение живёт коротко — в пределах вызова сервера, и после возврата на клиент на него рассчитывать нельзя.
  • 🔁 Адрес можно переиспользовать. Если вторым параметром передать уже полученный адрес, новое значение заменит старое по тому же адресу.
  • 🧪 Проверка формата. Функция ЭтоАдресВременногоХранилища(Строка) отвечает, похожа ли строка на адрес. Наличие данных по адресу она не гарантирует.

У управляемой формы есть свойство УникальныйИдентификатор. Именно его передают вторым параметром, чтобы файл не исчез между вызовами сервера.

Методы, которые возвращают адрес временного хранилища

Получить адрес можно несколькими способами. Выбор зависит от того, где находятся данные — на клиенте, на сервере или во внешней системе.

МетодГде вызываетсяЧто делаетКогда использовать
ПоместитьВоВременноеХранилищеклиент и серверкладёт значение, возвращает адресданные уже в памяти: двоичные данные, таблица, структура
НачатьПомещениеФайлаклиентпередаёт файл с компьютера пользователя на сервер, адрес приходит в обработчик оповещениязагрузка файла с диалогом выбора или по известному пути
НачатьПомещениеФайловклиентто же для нескольких файлов, адреса в массиве описанийпакетная загрузка
ПоместитьФайлклиентсинхронный вариант помещения файлатолько старые конфигурации с разрешённой модальностью
Асинхронные методы с суффиксом Асинхклиентпомещение файла через Ждатьплатформа 8.3.18 и новее, если конфигурация на них переведена

Обратные операции:

  • ПолучитьИзВременногоХранилища(Адрес) — вернуть значение на сервере или клиенте;
  • УдалитьИзВременногоХранилища(Адрес) — освободить память досрочно;
  • НачатьПолучениеФайлов(...) — сохранить данные по адресу в файл на компьютере пользователя.

Синхронные ПоместитьФайл и ПолучитьФайл с диалогом вызывают ошибку, если в свойствах конфигурации режим использования модальности установлен в «Не использовать». В типовых конфигурациях на «Такси» он запрещён, поэтому сразу пишите через Начать....

Пошагово: загрузить файл и получить его адрес

Разберём самый частый сценарий. Пользователь выбирает файл, он попадает на сервер, сервер читает содержимое.

Шаг 1. Реквизит формы под адрес

Добавьте на форму реквизит АдресФайла с типом Строка без ограничения длины. В нём адрес переживёт несколько вызовов сервера, пока форма открыта.

Шаг 2. Помещение файла на клиенте

&НаКлиенте
Процедура ЗагрузитьФайл(Команда)
    Оповещение = Новый ОписаниеОповещения("ЗагрузитьФайлЗавершение", ЭтотОбъект);
    НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры

&НаКлиенте
Процедура ЗагрузитьФайлЗавершение(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
    Если Не Результат Тогда
        Возврат; // пользователь отменил выбор
    КонецЕсли;
    АдресФайла = Адрес;
    ОбработатьФайлНаСервере(ВыбранноеИмяФайла);
КонецПроцедуры

Четвёртый параметр Истина открывает диалог выбора файла. Пятый — идентификатор формы, он задаёт время жизни данных.

Шаг 3. Чтение данных на сервере

&НаСервере
Процедура ОбработатьФайлНаСервере(ИмяФайлаНаКлиенте)
    Данные = ПолучитьИзВременногоХранилища(АдресФайла);
    Если ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Тогда
        ВызватьИсключение "Файл не найден во временном хранилище. Загрузите его заново.";
    КонецЕсли;

    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
    Данные.Записать(ИмяВременногоФайла);
    Попытка
        // разбор файла: ТабличныйДокумент.Прочитать, ЧтениеXML, ЧтениеТекста и т.д.
    Исключение
        УдалитьФайлы(ИмяВременногоФайла);
        ВызватьИсключение;
    КонецПопытки;
    УдалитьФайлы(ИмяВременногоФайла);
КонецПроцедуры

Многие форматы читаются только из файла на диске, поэтому двоичные данные сначала записывают во временный файл сервера.

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

Шаг 4. Освобождение памяти

После обработки вызовите УдалитьИзВременногоХранилища(АдресФайла) и очистите реквизит. Для файлов на десятки мегабайт это заметно разгружает память рабочего процесса.

Обратная задача: отдать файл пользователю

Сервер формирует файл, кладёт его в хранилище и возвращает адрес. Клиент сохраняет данные на диск.

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

&НаКлиенте
Процедура Выгрузить(Команда)
    Адрес = СформироватьВыгрузку();
    Файлы = Новый Массив;
    Файлы.Добавить(Новый ОписаниеПередаваемогоФайла("vygruzka.txt", Адрес));
    НачатьПолучениеФайлов(Новый ОписаниеОповещения("ВыгрузитьЗавершение", ЭтотОбъект), Файлы, , Истина);
КонецПроцедуры

&НаКлиенте
Процедура ВыгрузитьЗавершение(ПолученныеФайлы, ДополнительныеПараметры) Экспорт
    // ПолученныеФайлы = Неопределено, если пользователь отменил сохранение
КонецПроцедуры

В конфигурациях на БСП есть готовые обёртки ФайловаяСистемаКлиент.ЗагрузитьФайл и ФайловаяСистемаКлиент.СохранитьФайл. Они сами выбирают синхронный или асинхронный путь и учитывают веб-клиент.

Показать картинку по адресу на форме

Адрес временного хранилища умеет отображать поле картинки. Это удобно для предпросмотра скана или фото товара до записи в базу.

  1. Добавьте на форму реквизит АдресКартинки типа Строка.
  2. Перетащите его на форму и в свойствах элемента выберите вид «Поле картинки».
  3. На сервере поместите двоичные данные изображения в хранилище и запишите адрес в реквизит.
&НаСервере
Процедура ПоказатьКартинку(ДвоичныеДанныеКартинки)
    АдресКартинки = ПоместитьВоВременноеХранилище(ДвоичныеДанныеКартинки, УникальныйИдентификатор);
КонецПроцедуры

Поле само загрузит изображение по адресу. Пока форма открыта, картинка доступна. После записи в базу переключите поле на навигационную ссылку реквизита объекта, чтобы картинка не зависела от сеанса.

Адрес временного хранилища в HTTP-запросах и HTTP-сервисах

Здесь чаще всего путаются. Адрес временного хранилища — не URL. Внешняя система не может скачать по нему файл, а HTTP-сервис 1С работает в отдельном сеансе и тоже не видит чужое хранилище.

Поэтому схема всегда одна: хранилище служит транзитом внутри сеанса, а по сети передаются сами двоичные данные.

Скачать файл по HTTP и получить адрес

&НаСервере
Функция СкачатьВоВременноеХранилище()
    Соединение = Новый HTTPСоединение("example.com", 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL);
    Запрос = Новый HTTPЗапрос("/files/price.xlsx");
    Ответ = Соединение.Получить(Запрос);
    Если Ответ.КодСостояния <> 200 Тогда
        ВызватьИсключение СтрШаблон("Сервер вернул код %1", Ответ.КодСостояния);
    КонецЕсли;
    Данные = Ответ.ПолучитьТелоКакДвоичныеДанные();
    Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
КонецФункции

Таймаут 30 секунд защищает от зависания формы на медленном сервере. Полученный адрес клиент дальше использует так же, как адрес загруженного файла.

Отправить файл из хранилища во внешнюю систему

Запрос = Новый HTTPЗапрос("/api/upload");
Запрос.Заголовки.Вставить("Content-Type", "application/octet-stream");
Запрос.УстановитьТелоИзДвоичныхДанных(ПолучитьИзВременногоХранилища(АдресФайла));
Ответ = Соединение.ОтправитьДляОбработки(Запрос);

Отдать файл из HTTP-сервиса

Если внешней системе нужна ссылка на файл из 1С, публикуют HTTP-сервис. Обработчик метода читает данные из постоянного места (реквизит ХранилищеЗначения, присоединённый файл, каталог на сервере) и возвращает их телом ответа:

Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "application/pdf");
Ответ.УстановитьТелоИзДвоичныхДанных(Данные);
Возврат Ответ;

Временное хранилище в обработчике HTTP-сервиса уместно только как промежуточный буфер в пределах одного запроса.

Адрес хранилища для фонового задания

Фоновое задание выполняется в отдельном сеансе, но записать результат по заранее выданному адресу оно может. На этом построены длительные операции в типовых конфигурациях.

&НаСервере
Функция ЗапуститьФормирование()
    АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);
    Параметры = Новый Массив;
    Параметры.Добавить(АдресРезультата);
    ФоновыеЗадания.Выполнить("МойСерверныйМодуль.СформироватьФайл", Параметры);
    Возврат АдресРезультата;
КонецФункции

В экспортной процедуре общего модуля задание кладёт итог тем же методом: ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, АдресРезультата). Форма периодически проверяет состояние задания и, когда оно завершилось, забирает результат по адресу.

Резервируйте адрес с идентификатором формы до запуска задания. Если адрес создан без него, данные могут исчезнуть раньше, чем задание закончит работу.

Ошибки при работе с адресом временного хранилища

Диагностика: выберите симптом

Ещё две ошибки, которые не дают сообщения, но ломают логику:

  • ❌ Тип не проверен. ПолучитьИзВременногоХранилища возвращает то, что положили. Если там таблица значений, а код ждёт двоичные данные, падение будет ниже по коду и с невнятным текстом. Проверяйте ТипЗнч сразу после получения.
  • ❌ В хранилище кладут несериализуемое. Объект ДокументОбъект, HTTPСоединение, ЗаписьXML в хранилище не передаются. Кладите ссылки, двоичные данные, структуры и коллекции из примитивных типов.

Временное хранилище или другие способы хранения файлов

Временное хранилище хорошо как транзит. Для всего, что должно пережить сеанс, нужны другие механизмы.

СпособВремя жизниВидно другим сеансамПодходит для
Временное хранилищедо закрытия формы или конца вызованетпередача файла между клиентом, сервером и фоновым заданием
Реквизит ХранилищеЗначенияпостоянно, в базедавложения к документам, небольшие файлы
Присоединённые файлы БСПпостоянно, в базе или в томахдатиповой механизм файлов в конфигурациях на БСП
Тома хранения файлов на дискепостояннодабольшие объёмы, чтобы не раздувать базу
Временный файл ПолучитьИмяВременногоФайладо удаления, только на этой машиненетразбор форматов, которые читаются только с диска
Параметр вызова сервераодин вызовнетмаленькие данные, строки, числа

Правило выбора простое. Нужно донести данные из точки А в точку Б внутри работы пользователя — временное хранилище. Нужно, чтобы файл открыл кто-то завтра или внешняя система — сохраняйте его в базу или на диск и отдавайте через HTTP-сервис.

Передача таблицы значений на 50 000 строк через адрес временного хранилища вместо параметра серверной процедуры убирает её из контекста формы. Форма открывается и перерисовывается быстрее, потому что лишние данные не гоняются с каждым вызовом.

Частые вопросы

Можно ли получить адрес временного хранилища на клиенте без вызова сервера?
Да. ПоместитьВоВременноеХранилище доступен на клиенте, а НачатьПомещениеФайла возвращает адрес в обработчик оповещения. Сами данные всё равно уходят на сервер.
Сколько живут данные, помещённые с идентификатором формы?
Пока открыта форма, чей УникальныйИдентификатор передан. После её закрытия платформа очищает данные сама.
Можно ли передать адрес в другой сеанс или другому пользователю?
Нет. Адрес действует в сеансе, где получен. Исключение — фоновое задание, запущенное из этого сеанса и пишущее по заранее выданному адресу.
Чем адрес временного хранилища отличается от навигационной ссылки?
Навигационная ссылка указывает на объект базы и работает постоянно. Адрес временного хранилища указывает на данные в памяти сеанса и пропадает вместе с ними.
Есть ли ограничение на размер файла во временном хранилище?
Жёсткого лимита в коде нет, но всё лежит в памяти рабочего процесса. Файлы на сотни мегабайт лучше передавать частями или сохранять в том на диске.