К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как получить двоичные данные из хранилища значений в 1С

Как извлечь двоичные данные из хранилища значений в 1С: метод Получить(), работа с картинками и файлами, типовые ошибки и примеры кода на встроенном языке.

Хранилище значений (ХранилищеЗначения) в 1С — специальный тип данных, который позволяет сохранять в поле базы практически любые объекты: картинки, файлы, табличные документы, сериализованные структуры. Чаще всего в нём хранят двоичные данные — содержимое файлов, изображений, вложений писем. Задача извлечения этих данных возникает при выгрузке файлов на диск, отображении картинок в формах, обмене с внешними системами.

Основной инструмент извлечения — метод Получить() объекта ХранилищеЗначения. Он возвращает то значение, которое было помещено в хранилище при записи. Если туда сохраняли двоичные данные, метод вернёт объект типа ДвоичныеДанные, с которым уже можно работать: записывать в файл, передавать в картинку, конвертировать в Base64.

Типовая цепочка выглядит так: прочитать значение реквизита из объекта базы → вызвать Получить() → получить двоичные данные → использовать их по назначению. На каждом шаге есть нюансы: значение может быть пустым, хранилище может содержать не двоичные данные, а другой тип, а при работе через запрос результат нужно правильно развернуть.

Что находится внутри хранилища значений

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

Метод Получить() возвращает значение ровно в том виде, в каком его поместили через конструктор Новый ХранилищеЗначения(Значение). Если при записи туда положили двоичные данные — вернутся двоичные данные. Если положили строку или картинку — вернётся строка или картинка. Если хранилище пустое, метод вернёт Неопределено.

Базовый способ: метод Получить()

Самый простой сценарий — извлечение из реквизита объекта, например из справочника с файлами. Реквизит имеет тип ХранилищеЗначения, и обращение к нему даёт объект хранилища, у которого вызывается Получить().

ОбъектФайл = СсылкаНаФайл.ПолучитьОбъект();

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

Если ДвоичныеДанные = Неопределено Тогда

Сообщить("Хранилище пустое, файл не сохранён");

ИначеЕсли ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда

ДвоичныеДанные.Записать("C:\Temp\" + ОбъектФайл.ИмяФайла);

КонецЕсли;

Обратите внимание на двойную проверку: сначала на Неопределено, затем на тип. Если в хранилище по ошибке записали, например, строку с путём к файлу, попытка вызвать Записать() у неё вызовет исключение. Проверка типа через ТипЗнч() защищает от таких сбоев.

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

Порядок извлечения двоичных данных
  1. 1
    Получите объект или выборку с реквизитом типа ХранилищеЗначения
  2. 2
    Вызовите метод Получить() у значения реквизита
  3. 3
    Проверьте результат на Неопределено
  4. 4
    Проверьте тип результата через ТипЗнч()
  5. 5
    Запишите данные в файл методом Записать() или используйте иначе

Получение данных через запрос

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Файлы.ИмяФайла,

| Файлы.ДанныеФайла

|ИЗ

| Справочник.ПрисоединенныеФайлы КАК Файлы

|ГДЕ

| Файлы.Владелец = &Владелец";

Запрос.УстановитьПараметр("Владелец", ВладелецФайлов);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

ДвоичныеДанные = Выборка.ДанныеФайла.Получить();

Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда

ДвоичныеДанные.Записать(КаталогВыгрузки + Выборка.ИмяФайла);

КонецЕсли;

КонецЦикла;

Тип поля в выборке остаётся ХранилищеЗначения — запрос не распаковывает содержимое автоматически. Это частая причина замешательства у начинающих разработчиков: они видят в отладчике «ХранилищеЗначения» вместо ожидаемых двоичных данных и считают, что запрос вернул не то. На самом деле нужно просто вызвать Получить().

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

Работа с картинками и отображение в форме

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

ДвоичныеДанные = Объект.Картинка.Получить();

Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда

АдресКартинки = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);

КонецЕсли;

Реквизит формы АдресКартинки (строка) привязывается к полю картинки, и изображение отображается без промежуточного файла. Если требуется объект Картинка, его создают конструктором: Новый Картинка(ДвоичныеДанные). Это удобно для вывода в табличный документ при печати.

Конвертация в Base64 и обратно

При обмене через HTTP-сервисы и веб-сервисы двоичные данные передают в текстовом виде — обычно в формате Base64. Встроенный язык предоставляет функции Base64Строка() и Base64Значение() для двусторонней конвертации.

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

СтрокаBase64 = Base64Строка(ДвоичныеДанные);

// Обратное преобразование

ДанныеИзСтроки = Base64Значение(СтрокаBase64);

ДанныеИзСтроки.Записать("C:\Temp\restored.pdf");

Учтите, что Base64 увеличивает объём данных примерно на треть. Для больших файлов это критично: строка занимает память целиком, и при передаче десятков мегабайт возможны ошибки нехватки памяти. В таких случаях лучше передавать файл напрямую через двоичное тело HTTP-запроса.

Способы использования извлечённых данных

Запись в файл (Записать)

Подходит для выгрузки на диск и дальнейшей передачи. Ограничение: нужны права на каталог и свободное место.

Временное хранилище

Подходит для показа картинок и скачивания из веб-клиента. Ограничение: адрес недолговечен.

Base64-строка

Подходит для обмена через HTTP и JSON. Ограничение: рост объёма и расход памяти на больших файлах.

Типичные ошибки и их диагностика

Самая частая ошибка — попытка вызвать Получить() у значения, которое не является хранилищем. Это происходит, когда разработчик обращается к реквизиту через выборку запроса с соединениями или когда тип реквизита составной. Симптом — исключение «Метод объекта не обнаружен (Получить)». Лечится проверкой типа значения реквизита до вызова метода.

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

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

Типичные ошибки
01
Вызов Получить() без проверки типа реквизита — исключение «метод не обнаружен»
02
Отсутствие проверки на Неопределено — падение при попытке записать пустые данные в файл
03
Включение поля хранилища в запрос «про запас» — лишняя нагрузка на базу при больших файлах
04
Сохранение адреса временного хранилища в базу — битые ссылки после перезапуска сеанса
05
Поиск данных не в том реквизите: в типовых конфигурациях файлы часто лежат в регистре сведений, а не в справочнике

Где искать данные в типовых конфигурациях

В конфигурациях на БСП (Библиотека стандартных подсистем) присоединённые файлы хранятся не напрямую в справочнике файлов. Сам справочник содержит метаданные — имя, расширение, размер, — а двоичные данные лежат в регистре сведений, например «ДвоичныеДанныеФайлов» или аналогичном, либо в томе хранения файлов, если включено хранение на диске.

Правильный путь для типовых — использовать программный интерфейс БСП: функции модуля РаботаСФайлами (в новых версиях — РаботаСФайлами.ДвоичныеДанныеФайла(ПрисоединенныйФайл)). Это избавляет от привязки к конкретной структуре хранения, которая может меняться между версиями библиотеки. Прямое обращение к регистрам оправдано только в собственных разработках, где вы контролируете структуру.

Проверка результата и ограничения

После извлечения полезно убедиться, что данные корректны. Для двоичных данных доступен размер через метод Размер() — нулевой размер указывает на пустые данные. Если известен ожидаемый формат, можно проверить сигнатуру: например, PDF начинается с символов %PDF, ZIP-архив — с байтов PK. Такая проверка помогает отсеять повреждённые записи при массовой выгрузке.

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

Контрольные точки

Как проверить результат

Результат Получить()
Норма

Объект типа ДвоичныеДанные с размером больше нуля

Тревожный признак

Неопределено или другой тип значения

Записанный файл
Норма

Файл открывается штатной программой, размер совпадает с ожидаемым

Тревожный признак

Файл нулевого размера или не открывается

Картинка в форме
Норма

Изображение отображается после помещения во временное хранилище

Тревожный признак

Пустое поле картинки или ошибка формата

Итог

Что важно запомнить

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

Частые вопросы

Что возвращает Получить(), если хранилище пустое?

Метод возвращает Неопределено. Поэтому перед любым использованием результата нужна проверка: Если Данные = Неопределено Тогда ... — иначе попытка записать данные в файл или создать картинку завершится исключением.

Можно ли прочитать содержимое хранилища без Получить()?

Нет, штатного способа частичного чтения нет. Хранилище значений — непрозрачный контейнер: содержимое извлекается только целиком методом Получить(). Запросы и СКД также возвращают поле как объект хранилища, который затем распаковывается тем же методом.

Почему Получить() возвращает строку, хотя загружался файл?

Значит, при записи в хранилище поместили не двоичные данные, а строку — например, путь к файлу или Base64-представление. Проверьте код записи: корректный вариант — Новый ХранилищеЗначения(Новый ДвоичныеДанные(ПутьКФайлу)). Если внутри Base64-строка, преобразуйте её функцией Base64Значение().

Как получить файл из присоединённых файлов в типовой конфигурации?

Используйте функцию РаботаСФайлами.ДвоичныеДанныеФайла(СсылкаНаФайл) из БСП. Она сама определяет, где лежат данные — в информационной базе или в томе на диске. Прямое обращение к регистрам сведений хрупко и может сломаться при обновлении конфигурации.

Как выгрузить все файлы из хранилища на диск массово?

Выполните запрос по нужной таблице с полем хранилища, в цикле по выборке вызывайте Получить(), проверяйте тип и записывайте через ДвоичныеДанные.Записать(Путь). Для больших объёмов обрабатывайте записи порциями, чтобы не переполнить память сервера, и формируйте уникальные имена файлов, чтобы избежать перезаписи.

Работает ли Получить() на клиенте в тонком клиенте?

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