В практике разработки на платформе 1С:Предприятие 8.3 часто возникает необходимость передачи файлов между клиентом и сервером. Для этих целей используется механизм временного хранилища. Однако у начинающих разработчиков часто возникает путаница: что является адресом файла, можно ли использовать УникальныйИдентификатор для получения данных и как долго эти данные там хранятся. Рассмотрим эти вопросы подробно, проанализируем структуру адреса и разберем типичные архитектурные ошибки.
Для начала проанализируем синтаксис основной функции, с которой начинается работа. Когда мы вызываем метод ПоместитьВоВременноеХранилище, мы передаем данные и (опционально) адрес или идентификатор владельца. Рассмотрим типичный пример кода:
// Пример помещения двоичных данных во временное хранилище
ДанныеФайла = Новый ДвоичныеДанные("C:\temp\report.pdf");
АдресХранилища = ПоместитьВоВременноеХранилище(ДанныеФайла, Новый УникальныйИдентификатор());
Здесь кроется первое заблуждение. Параметр Адрес (второй аргумент функции) может принимать УникальныйИдентификатор. Многие полагают, что если передать туда свой GUID, то по нему же можно будет потом и забрать файл. Однако это не так. Рассмотрим, что происходит на самом деле:
УникальныйИдентификатор, система воспринимает его как идентификатор формы или владельца. Это определяет время жизни данных.e1cib/tempstorage/....ПолучитьИзВременногоХранилища необходимо использовать именно эту возвращенную строку, а не тот GUID, который вы передали в качестве владельца.Разберем, почему адрес временного хранилища такой длинный (обычно около 100 символов и более). Посмотрим на типичный формат адреса:
e1cib/tempstorage/157261cf-3edc-4966-8213-1013f716267f?seanceId=72885707-f4be-487f-a4ee-4a8d6cc15e37
Проанализируем составляющие этой строки:
Важно понимать: параметр seanceId привязывает данные к конкретному сеансу. Это сделано для безопасности, чтобы один пользователь не мог получить доступ к временным файлам другого, просто угадав GUID. Именно из-за этой служебной информации адрес не помещается в стандартные поля ограниченной длины (например, в строковый ресурс регистра сведений длиной 50 символов).
Выясним причину, по которой данные из временного хранилища внезапно "исчезают". Время жизни объекта в tempstorage жестко ограничено. Рассмотрим три сценария:
УникальныйИдентификатор формы, данные будут удалены автоматически, как только пользователь закроет эту форму.УдалитьИзВременногоХранилища(Адрес). Это крайне полезно для оптимизации потребления оперативной памяти при работе с тяжелыми файлами.Проанализируем ситуацию, когда разработчик пытается записать адрес временного хранилища в базу данных (например, в ресурс регистра сведений). Это является грубой архитектурной ошибкой по нескольким причинам:
Во-первых, как мы уже выяснили, адрес динамический и содержит seanceId. После того как пользователь выйдет из системы и зайдет снова, идентификатор сеанса изменится, и старая ссылка в регистре станет бесполезной — по ней ничего нельзя будет получить.
Во-вторых, временное хранилище физически может находиться в оперативной памяти сервера. При любом регламентном перезапуске службы rphost или очистке временных папок сервера данные будут безвозвратно утеряны. Ссылка в регистре останется "битой".
В-третьих, ограничение длины строки (например, 50 символов) не позволяет хранить полный адрес. Попытка "обрезать" адрес или хранить только GUID данных лишает нас возможности программно восстановить работоспособную ссылку, так как мы не знаем seanceId.
Если ваша задача — сохранить файл так, чтобы он был доступен и завтра, и послезавтра, и другим пользователям, забудьте про временное хранилище для этих целей. Рассмотрим правильный алгоритм действий:
ПрисоединенныеФайлы) или используйте существующий в БСП.ХранилищеЗначения.Пример кода для сохранения данных из временного хранилища в базу:
// Предположим, АдресВХ пришел с клиента
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХ);
ОбъектФайл = Справочники.Файлы.СоздатьЭлемент();
ОбъектФайл.Наименование = "МойДокумент.pdf";
// Помещаем данные в ХранилищеЗначения
ОбъектФайл.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
ОбъектФайл.Записать();
Если же данные вам нужны только в рамках текущего сеанса, но вам неудобно передавать длинную строку адреса между процедурами, можно использовать временное соответствие в оперативной памяти (например, в параметрах сеанса или в глобальной переменной модуля).
Рассмотрим по шагам этот прием:
Соответствие на сервере.МоеСоответствие.Вставить(КороткийКлюч, РеальныйДлинныйАдрес).КороткийКлюч.ПолучитьИзВременногоХранилища.Важное примечание: Этот метод все равно не сделает данные постоянными. Он лишь поможет "спрятать" длинную ссылку внутри сеанса.
Посмотрим на ситуацию с фоновыми заданиями. Если вы поместили файл в хранилище в контексте формы и передали адрес в фоновое задание, оно может не увидеть эти данные. Почему? Потому что фоновое задание выполняется в собственном сеансе. Для корректной передачи данных в фоновое задание следует помещать их во временное хранилище без привязки к форме, используя в качестве идентификатора владельца новый УникальныйИдентификатор, не связанный с интерфейсом.
Подведем итог: использование временного хранилища — это мощный инструмент для оперативной работы с данными, но он требует четкого понимания границ применимости. Никогда не сохраняйте адреса вида e1cib/tempstorage/ в реквизиты базы данных, если планируете обращаться к этим данным за пределами текущего пользовательского сеанса.