Что такое ХранилищеЗначения
ХранилищеЗначения – специальный тип данных 1С:Платформы, появившийся еще в версии 8.0. Он позволяет хранить в базе любые сериализуемые значения – от таблиц значений и картинок до произвольных файлов (PDF, DOC, ZIP и т.д.). По сути, это «контейнер» для двоичных данных и других объектов: значение хранилища сохраняется непосредственно в файле базы (или на SQL-сервере), включается в резервные копии и выгрузки. Благодаря этому даже фотографии сотрудников или отчеты остаются с базой при переносе на новую машину. И всё это – в рамках одной записи, без внешних ссылок. Конечно, есть и минус: хранение больших файлов в базе может раздувать ее размер и снижать быстродействие. Но при разумном подходе плюсы перевешивают.
Конструктор и создание значения по файлу
Чтобы поместить данные в ХранилищеЗначения, используется конструктор. Он вызывается так:
Новый ХранилищеЗначени(Значение [, АлгоритмСжатияДанных])
Например, если нужно записать в хранилище файл на диске, сначала создают объект ДвоичныеДанные по пути к файлу, а затем упаковывают его в хранилище:
Файл = "C:\\Документы\\Отчет.pdf"; ДвоичныеДанные = Новый ДвоичныеДанные(Файл); Хранилище = Новый ХранилищеЗначения(ДвоичныеДанные);
В этом примере файл «Отчет.pdf» считывается как двоичные данные и сохраняется в новый объект ХранилищеЗначения. Аналогично можно хранить изображения и другие типы. К примеру, картинку используют так:
Изображение = Новый Картинка("C:\\Фото\\Сотрудник.png"); Хранилище = Новый ХранилищеЗначения(Изображение);
После создания объект «Хранилище» уже содержит ссылку на загруженный в память файл. Просто и удобно. А еще у конструктора есть второй необязательный параметр – объект СжатиеДанных. Он позволяет включить сжатие по алгоритму Deflation. Например:
Хранилище = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
Здесь 9 – максимальная степень сжатия (0 – без сжатия, -1 – по умолчанию, 1..9 – степень). Вы можете опустить второй параметр, тогда сжатие по умолчанию (обычно – минимальное или отсутствует). Важно: создание хранилища происходит на сервере 1С, поскольку работа с файлами производится там.
(Немного вольности: просто даем объекту файл – и он его «упаковывает». Вот как это бывает в реальной жизни: кинул файл в хранилище – и забыл про него.)
Сохранение на диск значения из ХранилищаЗначений
Как только данные загружены в ХранилищеЗначения (например, при записи реквизита справочника или документа), возникает обратная задача – достать их оттуда и, скажем, сохранить на диск. В 1С для этого применяется метод Получить(). Он возвращает исходное значение, помещенное в хранилище. Порядок такой:
// Пусть "Хранилище" – это объект ХранилищеЗначения из реквизита справочника Результат = Хранилище.Получить(); // Если это двоичные данные (файл), то получаем ДвоичныеДанные: ДвоичныеДанные = Результат; // Сохраним файл на диск под новым именем: ИмяФайла = "C:\\temp\\НовыйОтчет.pdf"; ДвоичныеДанные.Записать(ИмяФайла);
Здесь мы предположили, что хранилище содержало ДвоичныеДанные (файл). Метод Получить() вернул именно объект ДвоичныеДанные. Дальше вызов Записать() создаст файл на диске. Если же в ХранилищеЗначения изначально лежали не бинарные данные, а, например, ТабличныйДокумент или Картинка, то Получить() вернет их объекты – и вы можете сразу передать их в нужный компонент.
Важный момент: просто обратиться к полю типа ХранилищеЗначения (как мы привыкли к простым реквизитам) нельзя. Только метод Получить() – и только один раз, на сервере. И еще: чтобы очистить хранилище, достаточно присвоить реквизиту значение Неопределено. Это стильно и коротко:
ОбъектСправочника.РеквизитХранилища = Неопределено;
Полезные методы и приёмы
У объекта ХранилищеЗначения, строго говоря, всего один метод – Получить(), и один конструктор. Но именно этого хватает, чтобы решать множество задач. Метод Получить() возвращает то, что вы туда положили (если в хранилище хранится ДвоичныеДанные или Картинка, получите соответствующий объект; если хранится таблица или текст – получите их). А с полученным объектом уже можно выполнять привычные операции: например, у ДвоичныеДанные есть Записать(), ЗаписатьВДвоичныеДанные(), ПолучитьСтрим(), а у Картинка – свои методы. Еще один приём: при обмене данными по веб-сервисам хранилище часто конвертируют в строку в формате Base64 через стандартную функцию XMLСтрока() – получается удобно передать файл в XML. Но это уже из серии тонких фишек, а базовое – запомните: Получить() и Записать().
Иногда возникает вопрос, как проверить, заполнено ли хранилище. Прямого способа в 1С нет. Пример нерабочего варианта:
Пусто = (Хранилище = Неопределено); // Не сработает, всегда будет False
Правильно так:
Данные = Хранилище.Получить(); ЕстьДанные = (Данные <> Неопределено);
Но он «дорогой», т.к. извлекает всё из базы. Обычно просто хранят отдельный флаг или проверяют размер полученных данных.
Кстати, звучит может тривиально, но на практике именно так: двумя методами – Конструктором и Получить() – охватывается основная работа с хранилищем.
Типовые задачи и примеры
В реальной разработке 1С с ХранилищемЗначений встречаются такие сценарии:
-
Хранение вложенного файла в справочнике или документе. Допустим, у вас есть справочник «Товары» с реквизитом «КаталогКартинок» типа «ХранилищеЗначения». Вы можете при загрузке формы взять путь к файлу картинки и запихнуть ее в хранилище:
Путь = ДиалогВыбораФайла.Выбрать(); Если Путь <> "" Тогда Изображение = Новый Картинка(Путь); ТоварОбъект.КаталогКартинок = Новый ХранилищеЗначения(Изображение); ТоварОбъект.Записать(); КонецЕсли;
А при открытии товара – доставать изображение обратно:
Если ТоварОбъект.КаталогКартинок <> Неопределено Тогда Картинка = ТоварОбъект.КаталогКартинок.Получить(); ПолеФормы.Картинка = Картинка; КонецЕсли;
Таким образом вы храните фотографии товаров прямо в базе, и при бэкапе они не потеряются.
-
Сохранение отчета или документа. Часто отчеты и внешние обработки являются *.epf/*.erf файлами. ХранилищеЗначения умеет хранить и их. Например:
Двоичка = Новый ДвоичныеДанные("C:\\Отчеты\\МойОтчет.epf"); ХЗОтчет = Новый ХранилищеЗначения(Двоичка, Новый СжатиеДанных(5)); ДокОбъект.ВнешняяОбработка = ХЗОтчет; ДокОбъект.Записать();
А чтобы запустить обработку из базы, делаем:
ДанныеОбработки = ДокОбъект.ВнешняяОбработка.Получить(); ВремФайл = КаталогВременныхФайлов() + "отчет.epf"; ДанныеОбработки.Записать(ВремФайл); ВнешОбраб = ВнешниеОбработки.Создать(ВремФайл); ВнешОбраб.ПолучитьФорму().Открыть();
Здесь мы берём двоичные данные из хранилища, записываем на диск и загружаем обработку динамически.
-
Обмен данными (веб-сервисы, XML). Иногда нужно передать файл через веб-сервис. Вместо того, чтобы вручную конвертировать в Base64, проще сначала получить ДвоичныеДанные, а они уже могут отдать строку:
СтрокаBase64 = Хранилище.Получить().ПолучитьСтрокуИзБайтов();
Правда, в сложных случаях используют
XMLСтрока()– это быстрый способ сериализовать содержимое хранилища в строку XML. -
Работа с табличными данными. Несмотря на название, в хранилище можно сохранять и ТабличныйДокумент или ТаблицаЗначений. Например, результат обработки можно упаковать и впоследствии выводить из хранилища. Пример:
// Сохраняем табличный документ в хранилище ТД = Новый ТабличныйДокумент; ТД.Вывести(ЭлементФормы.ТабличныйДокумент); ХЗ = Новый ХранилищеЗначения(ТД); ЭлементФормы.ТабДокументХЗ = ХЗ;
При необходимости его можно вытащить обратно из хранилища:
ТД = ЭлементФормы.ТабДокументХЗ.Получить(); Если ТД <> Неопределено Тогда ЭлементФормы.ТабличныйДокумент.Вывести(ТД); КонецЕсли;
Это позволяет сохранять результаты промежуточных вычислений или отчета в базе для последующего анализа.
Эти примеры – лишь начало. Фактически, любые объекты, которые могут быть сериализованы в XML (картинки, документы, настройки и пр.), можно передать через ХранилищеЗначения. Да, иногда все это звучит необычно – но именно за счёт этой гибкости многие разработки остаются «переносимыми». Кроме перечисленного, часто используют хранилище для кэширования двоичных или конфигурационных данных между сеансами. В общем, вариантов предостаточно – решение диктуется задачей проекта.
Способ сжатия данных при создании ХранилищаЗначений
При создании ХранилищеЗначения мы упомянули объект СжатиеДанных. Он управляет степенью компрессии. Формально:
ХЗ = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(Степень));
Параметр «Степень» – число от 0 до 9 (или -1 для значения по умолчанию). 0 означает отключить сжатие (тогда данные сохраняются « как есть»), а 9 – максимальная компрессия (медленнее обработка, но меньше размер). По умолчанию (СжатиеДанных() без параметра или -1) стоит некий компромисс: обычно небольшой уровень сжатия.
Например, если мы храним большой PDF-файл и хотим сжать его, код будет таким:
ДвоичныеДанные = Новый ДвоичныеДанные("C:\\БольшойДокумент.pdf"); Сжатие = Новый СжатиеДанных(9); // высокая степень ХЗ = Новый ХранилищеЗначения(ДвоичныеДанные, Сжатие);
После этого внутри хранилища файл займет меньше места. Правда, на запись и чтение уйдет чуть больше времени – особенно при большой степени сжатия. Рекомендуем: если скорость важнее, выбирайте 1–3; если экономия места критична – 7–9. Не забывайте, что сжатие учитывается при резервном копировании и может влиять на размер 1CD или БД на SQL-сервере.
В целом же стоит запомнить: стандартный алгоритм – Deflate, и он встроен в платформу. Преимущество – работает «из коробки», недостаток – дополнительная загрузка процессора при использовании. И да, иногда можно пренебречь, особенно если файлы небольшие и вы не экономите место (тогда можно просто писать без второго параметра, то есть без сжатия).
Итоги и открытые вопросы
ХранилищеЗначения – мощный инструмент для работы с любыми данными «в потоке» 1С. Оно превращает обычную БД в удобный файловый архив: в базе оказываются и таблицы, и документы, и картинки, и что угодно еще. Простота двух действий – записать через конструктор и извлечь через Получить() – скрывает большую гибкость. Причем всё это легко использовать без сложных настроек и вовлекать в процессы обработки.
Конечно, стоит помнить, что базы не резиновые: не нужно грузить в реквизиты десятки мегабайт чужих файлов без особой нужды. Но если вы храните по 1–2 изображения на объект или настройки документов, ХранилищеЗначения окажется очень удобным. В общем, всегда думайте: может ли данные проще положить в поле «хранилище», вместо того чтобы возиться с внешними файлами. На практике это часто упрощает сопровождение решений.
Так что следующий шаг за вами: попробовать вставить ХранилищеЗначения в свой сценарий. Будь то загрузка фотографий из документа, передача файла через веб-сервис или любое другое хранилище бинарных данных – чем раньше вы его опробуете, тем быстрее оцените. А вы уже использовали ХранилищеЗначения в своих проектах? Как считаете, можно ли обойтись без него и чем оно может удивить вас в будущем?













































