Работа с ХранилищеЗначения является одной из фундаментальных задач при разработке на платформе 1С:Предприятие 8. Часто возникает необходимость не просто хранить файл внутри базы данных, но и извлекать его для редактирования, отправки по почте или передачи в другую информационную базу. В среде управляемых форм этот процесс имеет свои особенности, связанные с разделением контекста на клиент и сервер.
В данной статье мы подробно разберем, как правильно извлечь данные из хранилища, сохранить их во временный файл, а также как реализовать механизм «упаковки» и обмена данными между различными конфигурациями.
Для начала проанализируем, как устроено ХранилищеЗначения. Этот объект предназначен для хранения произвольных данных (чисел, строк, структур, картинок или двоичных данных файлов) в сжатом виде. Чтобы начать работу с файлом, который там находится, его необходимо извлечь.
Рассмотрим стандартный программный код для получения данных на стороне сервера. Мы предполагаем, что в реквизите объекта или записи регистра с именем ДанныеФайла хранится объект типа ХранилищеЗначения.
// Получаем объект из хранилища
ДвоичныеДанныеФайла = Объект.ДанныеФайла.Получить();
Если ТипЗнч(ДвоичныеДанныеФайла) = Тип("ДвоичныеДанные") Тогда
// Если внутри действительно лежат двоичные данные, мы можем с ними работать
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx"); // расширение зависит от типа файла
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
// Теперь файл записан на сервере по пути ИмяВременногоФайла
КонецЕсли;
Выясним важный нюанс: метод Получить() возвращает именно тот объект, который был помещен в хранилище. Если вы записывали туда файл, то вернется объект типа ДвоичныеДанные. Именно у этого объекта есть встроенный метод Записать(), принимающий в качестве параметра путь к файлу на диске.
В управляемых формах мы часто сталкиваемся с тем, что файл нужно не просто создать на сервере, а передать пользователю на компьютер. Рассмотрим по шагам, как выглядит эта цепочка действий:
ХранилищеЗначения.ХранилищеЗначения в БД) с помощью функции ПоместитьВоВременноеХранилище(). Это создает временный адрес (строку).Проанализируем пример кода для передачи файла на клиент:
&НаСервере
Функция ПодготовитьФайлКСкачиваниюНаСервере()
Данные = Объект.Хранилище.Получить();
Если Данные = Неопределено Тогда
Возврат "";
КонецЕсли;
// Помещаем во временное хранилище сеанса
Возврат ПоместитьВоВременноеХранилище(Данные, ЭтаФорма.УникальныйИдентификатор);
КонецФункции
&НаКлиенте
Процедура СохранитьФайл(Команда)
АдресФайла = ПодготовитьФайлКСкачиваниюНаСервере();
Если Не ПустаяСтрока(АдресФайла) Тогда
// В современных версиях используем асинхронные методы
ПараметрыПолучения = Новый ПараметрыПолученияФайла;
НачатьПолучениеФайлаССервера(АдресФайла, "Отчет.pdf", ПараметрыПолучения);
КонецЕсли;
КонецПроцедуры
Обратите внимание на использование НачатьПолучениеФайлаССервера. В платформе 8.3 рекомендуется использовать именно асинхронные вызовы, чтобы интерфейс программы не «зависал» во время передачи больших объемов данных.
Иногда под термином «упаковка» подразумевается сжатие нескольких файлов в один архив перед помещением в ХранилищеЗначения. Разберем, как это сделать с помощью встроенного объекта ЗаписьZipФайла.
Предположим, нам нужно упаковать текстовый документ:
ПутьКАрхиву = ПолучитьИмяВременногоФайла("zip");
Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
// Добавляем файл в архив
// Параметры: Путь к файлу, Режим сохранения путей, Пароль
Архив.Добавить(ПутьКТекстовомуФайлу, РежимСохраненияПутейZip.НеСохранятьПути);
Архив.Записать();
// Теперь читаем архив как двоичные данные и кладем в ХранилищеЗначения
ДвоичныеДанныеАрхива = Новый ДвоичныеДанные(ПутьКАрхиву);
Объект.Хранилище = Новый ХранилищеЗначения(ДвоичныеДанныеАрхива, СтепеньСжатия.Максимальная);
Здесь мы используем свойство СтепеньСжатия самого объекта ХранилищеЗначения. Платформа 1С автоматически сжимает данные (алгоритм zlib), поэтому двойное сжатие (сначала ZIP, потом Хранилище) может не дать большого выигрыша в размере, но ZIP удобен, если файлов несколько.
Перейдем к вопросу обмена данными между разными базами. Поскольку ХранилищеЗначения — это внутренний объект 1С, его нельзя напрямую передать через текстовый файл или Web-сервис. Его нужно сериализовать.
Способ 1: Использование Base64
Это самый популярный метод. Двоичные данные преобразуются в текстовую строку, которую можно вставить в XML или JSON.
// В базе-источнике:
Данные = Объект.Хранилище.Получить();
СтрокаBase64 = Base64Строка(Данные);
// Передаем эту строку через текстовый файл или API
// В базе-приемнике:
ДвоичныеДанные = Base64Значение(СтрокаBase64);
ОбъектПриемник.Хранилище = Новый ХранилищеЗначения(ДвоичныеДанные);
Способ 2: Работа через внешние файлы
Если конфигурации имеют доступ к общему сетевому ресурсу или FTP, схема упрощается. Рассмотрим этот вариант:
data.bin в общую папку.Новый ДвоичныеДанные(ПутьКФайлу).УдалитьФайлы().Проанализируем вопрос очистки ресурсов. Функции типа ПолучитьИмяВременногоФайла() просто резервируют уникальное имя в системной папке временных файлов, но не гарантируют моментального удаления самого файла после закрытия программы.
Соблюдайте следующие правила:
Попытка...Исключение при записи и чтении файлов на диске, так как права доступа могут быть ограничены.ХранилищеЗначения или переданы на клиент.Посмотрим на пример безопасного удаления:
ИмяФайла = ПолучитьИмяВременногоФайла("tmp");
Попытка
Данные.Записать(ИмяФайла);
// ... какие-то действия с файлом
Исключение
ЗаписьЖурналаРегистрации("Ошибка записи файла", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеОписаниеОшибки());
КонецПопытки;
// Обязательная очистка
УдалитьФайлы(ИмяФайла);
Таким образом, мы рассмотрели полный цикл работы с ХранилищеЗначения: от извлечения и записи во временные файлы до упаковки и передачи между независимыми системами. Использование этих методик позволит вам эффективно управлять файловыми данными в ваших разработках на платформе 1С.