Как правильно получить двоичные данные из временного хранилища в модуле менеджера и почему адрес может оказаться пустым?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Выясним причину потери данных

Чтобы понять суть проблемы, проанализируем механизм работы метода ПоместитьВоВременноеХранилище. Ключевую роль здесь играет второй параметр этого метода — адрес или уникальный идентификатор. Именно он определяет "время жизни" данных.

Рассмотрим три сценария жизненного цикла данных, которые влияют на доступность файла в модуле менеджера:

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

Решение 1: Использование долгоживущего адреса (Клиент -> Сервер)

Если ваша задача — передать файл с клиента (например, загруженный пользователем) в процедуру модуля менеджера, нам необходимо, чтобы данные "дожили" до момента выполнения кода в модуле. Рассмотрим, как это сделать правильно.

При помещении данных в хранилище нам нужно явно указать платформе, что эти данные не должны быть удалены сразу после возврата на клиент. Для этого используем конструкцию с созданием нового уникального идентификатора.

Посмотрим на пример правильного кода помещения данных:


// Создаем новый уникальный идентификатор, чтобы отвязать данные от краткосрочного контекста
АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные, Новый УникальныйИдентификатор);

Теперь, имея этот адрес, мы можем передать его в экспортную процедуру модуля менеджера. Данные гарантированно будут доступны.

Однако, обратите внимание на важный нюанс. Так как мы привязали данные к сеансу (используя Новый УникальныйИдентификатор), платформа не очистит их автоматически до закрытия 1С пользователем. Это создает риск утечки памяти. Поэтому хорошей практикой считается удаление данных сразу после их использования.

Разберем пример кода в модуле менеджера с последующей очисткой:


Функция ВыполнитьОбработкуФайла(АдресВХранилище) Экспорт
    
    // Получаем данные по адресу
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХранилище);
    
    // Выполняем полезную работу с данными
    Результат = РаспознатьДанные(ДвоичныеДанные);
    
    // Важно! Освобождаем память, так как адрес был создан на базе Нового УникальногоИдентификатора
    УдалитьИзВременногоХранилища(АдресВХранилище);
    
    Возврат Результат;
    
КонецФункции

Решение 2: Прямая передача данных (Сервер -> Сервер)

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

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

Рассмотрим пример, как это реализовать:


&НаСервере
Процедура ОбработатьЛокальныйФайл()
    
    ПутьКФайлу = "C:\Files\Audio.wav";
    
    // Читаем файл сразу в объект ДвоичныеДанные
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
    
    // Передаем сами данные, а не адрес
    Результат = Справочники.МойСправочник.ОтправитьНаРаспознавание(ДвоичныеДанныеФайла);
    
КонецПроцедуры

В модуле менеджера функция должна быть готова принять именно данные:


// Модуль менеджера
Функция ОтправитьНаРаспознавание(ВходящиеДанные) Экспорт
    // ВходящиеДанные здесь - это уже тип ДвоичныеДанные, а не строка адреса
    // Сразу приступаем к работе
    Возврат ВнешняяКомпонента.Распознать(ВходящиеДанные);
КонецФункции

Оптимизация и рекомендации по памяти

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

  1. Если файл очень большой (сотни мегабайт) и он уже лежит на диске сервера, чтение его через Новый ДвоичныеДанные(Путь) загрузит весь файл в оперативную память. В таких случаях лучше передать в функцию модуля менеджера просто строку — путь к файлу (например, "C:\Temp\File.big"), и работать с ним потоково, если это позволяет логика задачи.
  2. Для фоновых заданий правила меняются. Если вы запускаете фоновое задание, временное хранилище родительского сеанса там недоступно. Платформа скопирует данные в сеанс фонового задания только если вы передадите адрес хранилища в параметрах метода ФоновыеЗадания.Выполнить.

Таким образом, выбор решения зависит от того, где изначально находится файл (на клиенте или на сервере) и как долго нам нужно хранить эти данные. Используйте Новый УникальныйИдентификатор для надежной передачи с клиента, но не забывайте очищать память методом УдалитьИзВременногоХранилища.

← На главную