Как записать ХранилищеЗначения во временный файл и передать данные между базами в 1С

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

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

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

Механика извлечения данных из ХранилищаЗначения

Для начала проанализируем, как устроено ХранилищеЗначения. Этот объект предназначен для хранения произвольных данных (чисел, строк, структур, картинок или двоичных данных файлов) в сжатом виде. Чтобы начать работу с файлом, который там находится, его необходимо извлечь.

Рассмотрим стандартный программный код для получения данных на стороне сервера. Мы предполагаем, что в реквизите объекта или записи регистра с именем ДанныеФайла хранится объект типа ХранилищеЗначения.


// Получаем объект из хранилища
ДвоичныеДанныеФайла = Объект.ДанныеФайла.Получить();

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

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

Особенности работы в управляемом приложении (Клиент-Сервер)

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

  1. На сервере: Извлекаем данные из ХранилищеЗначения.
  2. На сервере: Помещаем эти данные во временное хранилище (не путать с ХранилищеЗначения в БД) с помощью функции ПоместитьВоВременноеХранилище(). Это создает временный адрес (строку).
  3. На клиенте: Используем этот адрес для скачивания файла на компьютер пользователя.

Проанализируем пример кода для передачи файла на клиент:


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

&НаКлиенте
Процедура СохранитьФайл(Команда)
    АдресФайла = ПодготовитьФайлКСкачиваниюНаСервере();
    
    Если Не ПустаяСтрока(АдресФайла) Тогда
        // В современных версиях используем асинхронные методы
        ПараметрыПолучения = Новый ПараметрыПолученияФайла;
        НачатьПолучениеФайлаССервера(АдресФайла, "Отчет.pdf", ПараметрыПолучения);
    КонецЕсли;
КонецПроцедуры

Обратите внимание на использование НачатьПолучениеФайлаССервера. В платформе 8.3 рекомендуется использовать именно асинхронные вызовы, чтобы интерфейс программы не «зависал» во время передачи больших объемов данных.

Упаковка и архивирование данных

Иногда под термином «упаковка» подразумевается сжатие нескольких файлов в один архив перед помещением в ХранилищеЗначения. Разберем, как это сделать с помощью встроенного объекта ЗаписьZipФайла.

Предположим, нам нужно упаковать текстовый документ:


ПутьКАрхиву = ПолучитьИмяВременногоФайла("zip");
Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);

// Добавляем файл в архив
// Параметры: Путь к файлу, Режим сохранения путей, Пароль
Архив.Добавить(ПутьКТекстовомуФайлу, РежимСохраненияПутейZip.НеСохранятьПути);
Архив.Записать();

// Теперь читаем архив как двоичные данные и кладем в ХранилищеЗначения
ДвоичныеДанныеАрхива = Новый ДвоичныеДанные(ПутьКАрхиву);
Объект.Хранилище = Новый ХранилищеЗначения(ДвоичныеДанныеАрхива, СтепеньСжатия.Максимальная);

Здесь мы используем свойство СтепеньСжатия самого объекта ХранилищеЗначения. Платформа 1С автоматически сжимает данные (алгоритм zlib), поэтому двойное сжатие (сначала ZIP, потом Хранилище) может не дать большого выигрыша в размере, но ZIP удобен, если файлов несколько.

Перенос данных между конфигурациями

Перейдем к вопросу обмена данными между разными базами. Поскольку ХранилищеЗначения — это внутренний объект 1С, его нельзя напрямую передать через текстовый файл или Web-сервис. Его нужно сериализовать.

Способ 1: Использование Base64

Это самый популярный метод. Двоичные данные преобразуются в текстовую строку, которую можно вставить в XML или JSON.


// В базе-источнике:
Данные = Объект.Хранилище.Получить();
СтрокаBase64 = Base64Строка(Данные);
// Передаем эту строку через текстовый файл или API

// В базе-приемнике:
ДвоичныеДанные = Base64Значение(СтрокаBase64);
ОбъектПриемник.Хранилище = Новый ХранилищеЗначения(ДвоичныеДанные);

Способ 2: Работа через внешние файлы

Если конфигурации имеют доступ к общему сетевому ресурсу или FTP, схема упрощается. Рассмотрим этот вариант:

  1. Первая база записывает данные из хранилища в файл data.bin в общую папку.
  2. Вторая база проверяет наличие файла и считывает его конструктором Новый ДвоичныеДанные(ПутьКФайлу).
  3. После прочтения файл удаляется методом УдалитьФайлы().

Важные рекомендации по работе с временными файлами

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

Соблюдайте следующие правила:

Посмотрим на пример безопасного удаления:


ИмяФайла = ПолучитьИмяВременногоФайла("tmp");
Попытка
    Данные.Записать(ИмяФайла);
    // ... какие-то действия с файлом
Исключение
    ЗаписьЖурналаРегистрации("Ошибка записи файла", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеОписаниеОшибки());
КонецПопытки;

// Обязательная очистка
УдалитьФайлы(ИмяФайла);

Таким образом, мы рассмотрели полный цикл работы с ХранилищеЗначения: от извлечения и записи во временные файлы до упаковки и передачи между независимыми системами. Использование этих методик позволит вам эффективно управлять файловыми данными в ваших разработках на платформе 1С.

← На главную