Разработка и Конфигурация · 11 мин
Как прочитать хранилище значений в 1С
Как прочитать хранилище значений в 1С: метод Получить(), работа с картинками, файлами и настройками, проверка на пустое значение, типичные ошибки и примеры кода.
Хранилище значений (тип ХранилищеЗначения) в 1С — это специальный контейнер, который позволяет сохранять в полях базы данных объекты, не имеющие собственного типа колонки: картинки, двоичные данные файлов, табличные документы, структуры настроек. Чтобы использовать такие данные, их нужно сначала извлечь — прочитать хранилище. Операция выполняется одним методом, но на практике вызывает вопросы: как проверить, что внутри не пусто, как определить тип содержимого, почему возвращается Неопределено.
Материал рассчитан на разработчиков и администраторов, которые работают с типовыми или самописными конфигурациями. Разберём чтение хранилища через запрос и через объект, обработку картинок и файлов, типичные ошибки и способы проверить результат. Примеры кода приведены для встроенного языка 1С и работают как в управляемых, так и в обычных формах.
Что такое хранилище значений и где оно встречается
Хранилище значения — это тип данных, который сериализует произвольный объект и сохраняет его в поле базы данных в виде двоичных данных. При записи объект «упаковывается» конструкцией Новый ХранилищеЗначения(Объект), при чтении — «распаковывается» методом Получить(). Само поле в таблице при этом содержит не исходный объект, а его сериализованное представление.
В типовых конфигурациях хранилище применяется повсеместно: фотографии сотрудников и товаров, присоединённые файлы, сохранённые настройки отчётов и вариантов, схемы компоновки данных, история изменений. Например, в справочнике «Физические лица» фотография обычно лежит в реквизите с типом ХранилищеЗначения, а настройки отчёта — в табличной части или регистре сведений.
Базовое чтение: метод Получить()
Основной сценарий выглядит так: получаете значение поля хранилища и вызываете у него метод Получить(). Если чтение идёт через объект (например, объект справочника), код минимален:
ОбъектСправочника = СсылкаНаЭлемент.ПолучитьОбъект();
Данные = ОбъектСправочника.ДанныеФайла.Получить();
Если Данные = Неопределено Тогда
Сообщить("Хранилище пустое");
Иначе
// работаем с данными
КонецЕсли;
Важно понимать: пока вы не вызвали Получить(), в переменной лежит объект типа ХранилищеЗначения, а не само содержимое. Попытка обратиться к нему как к картинке или строке приведёт к ошибке несоответствия типов. Метод Получить() автоматически восстанавливает исходный тип объекта — картинку, двоичные данные, структуру и так далее.
Если хранилище было создано с компрессией (Новый ХранилищеЗначения(Объект, Новый СжатиеДанных(9))), распаковка при чтении происходит прозрачно — указывать параметры сжатия при вызове Получить() не нужно.
Чтение хранилища через запрос
Когда данные нужны без изменения объекта, быстрее и безопаснее прочитать поле запросом — без вызова ПолучитьОбъект(), который блокирует запись и поднимает весь объект в память:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Файлы.ДанныеФайла КАК Хранилище
|ИЗ
| Справочник.Файлы КАК Файлы
|ГДЕ
| Файлы.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаФайл);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Данные = Выборка.Хранилище.Получить();
КонецЕсли;
Обратите внимание: запрос возвращает именно объект ХранилищеЗначения, поэтому Получить() всё равно обязателен. Распространённая ошибка — присвоить результат выборки напрямую в реквизит картинки или файла и получить сообщение о неверном типе.
При массовой обработке (например, выгрузке всех картинок номенклатуры) читайте хранилища по одному в цикле и сразу освобождайте данные. Загрузка десятков мегабайт бинарных данных в таблицу значений целиком может привести к перерасходу памяти на сервере.
Работа с типичным содержимым: картинки, файлы, настройки
Картинки
Если в хранилище записана картинка, после Получить() вы получаете объект типа Картинка. Для отображения в управляемой форме её обычно помещают во временное хранилище формы:
Картинка = Выборка.Фото.Получить();
Если Картинка <> Неопределено Тогда
АдресКартинки = ПоместитьВоВременноеХранилище(Картинка, УникальныйИдентификатор);
КонецЕсли;
Реквизит формы с адресом затем связывается с полем вида «Поле картинки». Если нужно сохранить картинку на диск, используйте её метод Записать(ИмяФайла) или преобразуйте в двоичные данные.
Файлы (двоичные данные)
Присоединённые файлы в типовых конфигурациях чаще всего хранятся как ДвоичныеДанные. После чтения их можно записать на диск:
ДвоичныеДанные = Выборка.ХранилищеФайла.Получить();
Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
ДвоичныеДанные.Записать("C:\Temp\" + ИмяФайла);
КонецЕсли;
Настройки и структуры
Отчёты и обработки часто сохраняют настройки в виде структуры, соответствия или объекта НастройкиКомпоновкиДанных. После чтения проверяйте тип и наличие ожидаемых ключей — формат настроек мог измениться между версиями конфигурации, и обращение к отсутствующему свойству вызовет исключение.
- 1Получите значение поля хранилища: через объект или запросом
- 2Вызовите у полученного значения метод Получить()
- 3Проверьте, что результат не равен Неопределено
- 4Проверьте тип результата функцией ТипЗнч(), если содержимое может различаться
- 5Обработайте данные по типу: картинку — в форму или файл, двоичные данные — методом Записать(), структуру — с проверкой ключей
Проверка результата и диагностика проблем
Главные причины, по которым чтение хранилища «не работает»: поле пустое, данные испорчены, либо код ожидает другой тип содержимого. Диагностику удобно строить по шагам — сначала убедиться, что поле вообще заполнено, затем проверить тип извлечённого объекта:
Данные = Выборка.Хранилище.Получить();
Если Данные = Неопределено Тогда
Сообщить("Хранилище пустое");
Иначе
Сообщить("Тип содержимого: " + ТипЗнч(Данные));
КонецЕсли;
Отдельный случай — ошибка «Ошибка формата потока» при вызове Получить(). Она означает, что сериализованные данные повреждены: например, запись в базу была прервана, или поле заполнялось внешними средствами напрямую в СУБД. Восстановить такое содержимое штатными средствами обычно нельзя — данные придётся загружать заново из источника.
Как проверить результат чтения
Объект ожидаемого типа (Картинка, ДвоичныеДанные, Структура)
Неопределено — хранилище пустое или не заполнялось
Совпадает с типом, который записывался
Другой тип — данные записаны другой версией кода или конфигурации
Выполняется без исключений
Ошибка формата потока — данные повреждены
Типичные ошибки и ограничения
Первая и самая частая ошибка — забыть вызвать Получить() и работать с объектом ХранилищеЗначения как с содержимым. Вторая — отсутствие проверки на Неопределено: при переборе справочника с частично заполненными картинками код падает на первом же пустом элементе.
Третья группа проблем связана с производительностью. Поля хранилищ тяжёлые: выбирать их запросом «на всякий случай» в списках и отчётах не стоит — это замедляет выборку и увеличивает трафик между сервером СУБД и сервером 1С. В динамических списках и отчётах СКД поле хранилища лучше вообще исключать из выборки, а читать только по требованию для конкретной строки.
Ещё одно ограничение: содержимое хранилища недоступно для поиска и сравнения в запросе. Нельзя отобрать записи условием по внутренностям хранилища — только по тому, заполнено поле или нет, и то косвенно. Если по данным нужен поиск, их следует дублировать в отдельных реквизитах.
Чтение хранилищ в типовых конфигурациях и через консоль
Если нужно разово посмотреть, что лежит в хранилище конкретного элемента, удобно использовать консоль кода (встроенную в некоторые конфигурации на БСП или внешнюю обработку-консоль запросов с возможностью выполнения кода). Достаточно выполнить запрос к полю и вывести ТипЗнч() результата — это быстро покажет, пустое хранилище или нет и что внутри.
В конфигурациях на Библиотеке стандартных подсистем присоединённые файлы рекомендуется читать не прямым обращением к реквизитам, а программным интерфейсом — функциями модуля работы с файлами (например, получением двоичных данных файла по ссылке). Это гарантирует корректную работу независимо от того, где физически хранится файл: в информационной базе или в томах на диске.
FAQ
Почему Получить() возвращает Неопределено, хотя поле выглядит заполненным?
Чаще всего поле на самом деле не заполнено — визуально это не проверить, потому что содержимое хранилища не отображается в формах списков. Выполните запрос к полю и проверьте результат Получить(). Если хранилище действительно должно быть заполнено, проверьте логику записи: возможно, объект записывался конструкцией без передачи значения.
Можно ли узнать, что лежит в хранилище, не извлекая данные?
Штатных средств для этого нет: тип содержимого становится известен только после вызова Получить() и проверки ТипЗнч(). Косвенно можно ориентироваться на прикладную логику — например, по имени реквизита и коду, который его записывает.
Как прочитать хранилище значений в запросе сразу для всех записей?
Выберите поле хранилища в запросе и в цикле по выборке вызывайте Получить() для каждой строки. Учитывайте объём: если хранятся файлы или картинки, массовая выборка может занять много памяти — обрабатывайте записи порциями.
Что делать при ошибке «Ошибка формата потока» при чтении?
Ошибка означает повреждение сериализованных данных. Проверьте, воспроизводится ли она на одной записи или на многих, выполните тестирование и исправление базы, а сами данные восстановите из резервной копии или загрузите заново. Записывать в такое поле новое значение штатными средствами можно — старое содержимое при этом безвозвратно заменяется.
Можно ли сравнить два хранилища значений между собой?
Прямого сравнения объектов ХранилищеЗначения нет. Практический способ — получить содержимое обоих через Получить() и сравнить уже его: для двоичных данных — побайтово или через хеш, для структур — по ключам, для строк — обычным сравнением.
Читается ли хранилище значений на тонком клиенте и в веб-клиенте?
Метод Получить() работает на сервере и в толстом клиенте. На тонком и веб-клиенте работа с хранилищем ограничена: данные следует извлекать в серверной процедуре и передавать на клиент уже готовый результат — адрес временного хранилища, двоичные данные или примитивные значения.
Что важно запомнить
Хранилище значений читается единственным способом — методом Получить(), вызванным у значения поля, полученного через объект или запрос. Всегда проверяйте результат на Неопределено и тип содержимого, не выбирайте поля хранилищ в массовых запросах без необходимости, а повреждённые данные восстанавливайте из копии, а не правкой в СУБД.