Как правильно сохранить файл в реквизит ХранилищеЗначения при сохранении формы

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача по загрузке внешних файлов (документов, сертификатов, архивов) в базу данных. Типичный сценарий: пользователь выбирает файл на диске, и этот файл должен быть сохранен в реквизит справочника или документа с типом ХранилищеЗначения. Однако начинающие разработчики часто сталкиваются с тем, что файл после сохранения оказывается «битым» или не открывается. Проанализируем ситуацию, выясним причины ошибок и разберем правильный алгоритм реализации этой задачи.

Почему нельзя сохранять двоичные данные в обычную строку

Рассмотрим распространенную ошибку: попытку считать файл, превратить его в строку и передать в реквизит формы для последующей записи на сервере. Когда мы пытаемся записать «сырые» байты файла в обычную текстовую строку 1С (которая использует кодировку Unicode), происходит необратимое искажение данных. Некоторые последовательности байтов интерпретируются как спецсимволы, другие просто теряются. В итоге, при обратном преобразовании строки в ДвоичныеДанные, мы получаем массив байтов, который уже не соответствует исходному файлу.

Важный момент: если по каким-то специфическим причинам вам абсолютно необходимо передать файл именно через текст, используйте кодирование Base64. В 1С для этого предусмотрены функции Base64Строка(ДвоичныеДанные) и Base64Значение(Строка). Это гарантирует целостность, хотя и увеличивает объем данных на 33%. Однако для стандартных задач загрузки файлов в 1С существует гораздо более эффективный механизм — Временное хранилище.

Алгоритм правильного сохранения файла

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

Шаг 1. Подготовка формы. Создадим на форме реквизит АдресФайлаВоВременномХранилище с типом Строка. В нем мы будем временно держать ссылку на данные, пока пользователь не нажмет кнопку «Записать».

Шаг 2. Загрузка файла на стороне клиента. Проанализируем код, который инициирует выбор файла и его передачу на сервер. Мы будем использовать асинхронный метод НачатьПомещениеФайлаНаСервер, так как это стандарт для современных конфигураций.


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

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

Шаг 3. Запись в объект на сервере. Теперь рассмотрим, как перенести данные из временного хранилища в реквизит объекта при записи формы. Это происходит в обработчике ПередЗаписьюНаСервере.


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

Нюансы управления временем жизни и памятью

Рассмотрим подробнее использование УникальногоИдентификатора формы. Если при вызове метода НачатьПомещениеФайлаНаСервер не указать идентификатор формы, данные во временном хранилище будут удалены сразу после завершения первого же серверного вызова. Привязав данные к форме, мы гарантируем, что файл будет доступен до тех пор, пока пользователь не закроет окно. Это критично, если пользователь сначала выбрал файл, а нажал «Записать» только через некоторое время.

Также проанализируем ситуацию со сжатием данных. Конструктор Новый ХранилищеЗначения позволяет управлять уровнем сжатия:

  1. Если вы сохраняете текстовые документы (TXT, XML, LOG), 1С эффективно их сожмет.
  2. Если же вы сохраняете файлы, которые уже сжаты (ZIP, PNG, JPEG, PDF), повторное сжатие не даст выигрыша в размере, но увеличит нагрузку на процессор. В таких случаях можно использовать Новый СжатиеДанных(0).

Рекомендации по хранению сопутствующих данных

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

Современный подход: Использование Асинхронности (8.3.15+)

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


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

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

← На главную