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

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

Как поместить файл в хранилище значений 1С

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

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

Механизм работает одинаково на всех актуальных версиях платформы 8.3: файл сначала считывается в объект типа ДвоичныеДанные, затем упаковывается через конструктор Новый ХранилищеЗначения() и записывается в реквизит объекта с типом «ХранилищеЗначения». Обратная операция — метод Получить() — возвращает исходные двоичные данные.

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

Подготовка: создание реквизита с типом «ХранилищеЗначения»

Прежде чем помещать файл, в конфигурации должен существовать реквизит, способный его принять. Откройте конфигуратор, найдите нужный объект (справочник, документ или создайте отдельный регистр сведений для вложений) и добавьте реквизит с типом «ХранилищеЗначения». Например, для справочника «Номенклатура» это может быть реквизит «ФайлКартинки».

Альтернатива — хранение файлов в томах на диске через механизм «Присоединенные файлы» из библиотеки стандартных подсистем (БСП). Если конфигурация построена на БСП, часто правильнее использовать штатную подсистему «Работа с файлами», а не писать собственный код. Хранилище значений оправдано, когда файлов немного, они небольшие и нужна максимально простая схема без дополнительных справочников.

Где хранить файл

Реквизит типа ХранилищеЗначения

Подходит для небольших файлов и простых решений; минус — рост размера базы и невозможность частичного чтения

БСП «Присоединенные файлы»

Стандарт для типовых конфигураций, поддержка версий и томов; требует подключенной подсистемы

Внешний каталог или сетевое хранилище

Подходит для больших архивов; минус — файл не защищён резервным копированием базы и правами 1С

Базовый код: помещение файла в хранилище значений

Ключевые объекты — ДвоичныеДанные и ХранилищеЗначения. Двоичные данные читают файл с диска, хранилище упаковывает их для записи в базу. Классический серверный вариант выглядит так:

&НаСервере

Процедура ПоместитьФайлВХранилище(СсылкаНаОбъект, ПутьКФайлу)

ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);

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

Объект.ФайлДанные = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));

Объект.Записать();

КонецПроцедуры

Параметр Новый СжатиеДанных(9) включает максимальное сжатие. Для уже сжатых форматов (JPG, ZIP, PDF с картинками) выигрыш минимален, а для XML, текста и BMP размер может уменьшиться в разы. Сжатие не меняет логику извлечения — метод Получить() сам вернёт распакованные данные.

Обратите внимание: запись выполняется через ПолучитьОбъект(), а не через установку значения реквизита формы. Изменение реквизита формы сохранится только после записи объекта, а при работе «напрямую» через ссылку объект нужно явно записать.

Помещение файла из клиентского приложения

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

&НаКлиенте

Процедура ВыбратьФайл(Команда)

ОписаниеОповещения = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);

НачатьПомещениеФайла(ОписаниеОповещения, , , Истина, УникальныйИдентификатор);

КонецПроцедуры

&НаКлиенте

Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДопПараметры) Экспорт

Если Результат Тогда

СохранитьФайлНаСервере(Адрес);

КонецЕсли;

КонецПроцедуры

&НаСервере

Процедура СохранитьФайлНаСервере(Адрес)

ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);

Объект = РеквизитФормыВЗначение("Объект");

Объект.ФайлДанные = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));

Объект.Записать();

КонецПроцедуры

Важный нюанс: ПолучитьИзВременногоХранилища возвращает именно двоичные данные, если файл помещался стандартным способом. Если же вы помещали туда что-то иное, проверьте тип возвращаемого значения перед упаковкой.

Извлечение файла и сохранение на диск

Обратная операция проста: метод Получить() у значения реквизита возвращает ровно те двоичные данные, которые были помещены, с учётом автоматической распаковки сжатия.

&НаСервере

Функция ПолучитьФайлИзХранилища(СсылкаНаОбъект) Экспорт

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

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

Возврат Неопределено;

КонецЕсли;

Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанные);

КонецФункции

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

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

Ограничения и влияние на базу данных

Каждый файл, помещённый в хранилище значений, физически увеличивает размер информационной базы. В файловом варианте таблица с большими вложениями быстро раздувает файл 1Cv8.1CD, что замедляет резервное копирование, тестирование и обновление. В клиент-серверном варианте растут таблицы СУБД и журналы транзакций.

Практические рекомендации: не храните в хранилище значений файлы размером в десятки и сотни мегабайт, используйте сжатие для текстовых и XML-данных, а при массовой загрузке вложений рассмотрите тома хранения файлов БСП. Также учтите, что реквизит типа «ХранилищеЗначения» нельзя индексировать и использовать в отборах запроса осмысленным образом — поиск по содержимому файлов невозможен.

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

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

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

Типичные ошибки
01
Присвоение реквизиту ДвоичныхДанных без обёртки ХранилищеЗначения — ошибка несоответствия типов при записи
02
Чтение файла по клиентскому пути в серверной процедуре — файл не найден, так как сервер не видит диск пользователя
03
Отсутствие проверки Получить() на Неопределено — падение кода на объектах без вложения
04
Хранение имени файла только в пути — после помещения оригинальное имя и расширение теряются
05
Загрузка больших файлов без сжатия и без оценки роста базы — раздувание базы и медленные бэкапы

Проверка результата

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

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

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

Значение Получить() после записи
Норма

Возвращаются ДвоичныеДанные, размер совпадает с исходным файлом

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

Неопределено или размер равен нулю — запись не состоялась

Открытие извлечённого файла
Норма

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

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

Файл повреждён или не открывается — проверьте, не записали ли вы строку вместо двоичных данных

Размер базы после загрузки
Норма

Прирост соответствует суммарному объёму файлов с учётом сжатия

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

Резкий скачок размера — стоит пересмотреть подход к хранению

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

Итог

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

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

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

Можно ли хранить в хранилище значений не файл, а другие данные?

Да. Хранилище значений принимает почти любые сериализуемые объекты: таблицы значений, структуры, массивы, картинки. Ограничение — данные должны поддерживать сериализацию платформой; например, COM-объекты и открытые соединения сохранить нельзя.

Как узнать размер файла внутри хранилища без извлечения?

Штатного способа прочитать размер без вызова Получить() нет. Практичное решение — при записи сохранять размер в отдельном числовом реквизите и использовать его для отображения и контроля.

Что делает параметр сжатия и всегда ли его использовать?

СжатиеДанных уменьшает объём данных при записи в базу. Для текстовых форматов, XML и несжатых изображений выигрыш значительный. Для JPG, ZIP и видео сжатие почти бесполезно, но и не вредит — его можно оставить включённым по умолчанию.

Можно ли найти все объекты, у которых хранилище пустое?

Да, запросом с условием вида «НЕ Хранилище ЕСТЬ NULL» проверяется заполненность, но содержимое сравнить нельзя. На практике удобнее завести отдельный булев реквизит «ЕстьВложение» и отбирать по нему — это работает быстрее и прозрачнее.

Чем хранилище значений отличается от временного хранилища?

Хранилище значений — тип данных для постоянного сохранения в реквизитах базы. Временное хранилище — механизм передачи данных между клиентом и сервером в рамках сеанса или формы; его содержимое удаляется автоматически и не предназначено для долговременного хранения.

Будет ли работать этот код в типовой конфигурации без доработок?

Код универсален для платформы 8.3, но реквизит с типом «ХранилищеЗначения» в типовом объекте придётся добавить через расширение или доработку конфигурации. Если конфигурация на БСП, рассмотрите штатный механизм присоединенных файлов — он уже реализует загрузку, версии и хранение в томах.