Разработка и Конфигурация · 12 мин
Как получить файл из хранилища значений в 1С
Как извлечь файл из хранилища значений в 1С: метод Получить(), работа с двоичными данными, сохранение на диск, типичные ошибки и готовые примеры кода.
Хранилище значений (ValueStorage) в 1С — универсальный механизм для сохранения произвольных данных: файлов, картинок, табличных документов, сериализованных объектов. В конфигурациях его используют для присоединенных файлов, логотипов, печатных форм и обмена данными. Чтобы получить файл обратно, нужно вызвать метод Получить() у значения реквизита с типом «ХранилищеЗначения» и дальше работать с результатом — чаще всего это двоичные данные или объект встроенного языка.
Главная сложность для начинающих разработчиков — понимание того, что хранилище возвращает данные в том виде, в каком их туда поместили. Если сохраняли двоичные данные файла — получите двоичные данные. Если помещали табличный документ или структуру через сериализацию — получите именно этот объект. Поэтому перед извлечением полезно знать, что записано в конкретный реквизит.
Ниже разобраны основные сценарии: извлечение файла на диск, передача его клиенту через временное хранилище, чтение из типовых механизмов присоединенных файлов, а также типичные ошибки и способы их диагностики.
Как устроено хранилище значений и что оно возвращает
Реквизит с типом «ХранилищеЗначения» физически хранит данные в базе в сжатом сериализованном виде. При чтении объекта из базы содержимое хранилища не распаковывается автоматически — извлечение происходит только при явном вызове метода Получить(). Это важно для производительности: запрос, выбирающий ссылку, не тащит за собой мегабайты бинарных данных, пока они реально не понадобились.
Метод Получить() возвращает значение того типа, который был помещён при записи. На практике чаще всего встречаются три варианта: ДвоичныеДанные (содержимое файла), строка (например, XML или JSON) и сериализованные объекты вроде ТабличныйДокумент, Картинка или произвольной структуры. Определить тип результата можно функцией ТипЗнч().
Базовый сценарий: извлечь файл и сохранить на диск
Самая частая задача — достать файл из реквизита справочника или документа и записать его в каталог на диске. Порядок действий: получить объект по ссылке, вызвать Получить(), проверить тип результата и вызвать метод Записать() у двоичных данных.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПрисоединенныеФайлы.Файл КАК Файл
|ИЗ
| Справочник.ПрисоединенныеФайлы КАК ПрисоединенныеФайлы
|ГДЕ
| ПрисоединенныеФайлы.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ФайлСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Данные = Выборка.Файл.Получить();
Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда
Данные.Записать("C:\Temp\извлеченный_файл.pdf");
КонецЕсли;
КонецЕсли;
Обратите внимание на проверку типа: без неё попытка вызвать Записать() у строки или табличного документа приведёт к ошибке выполнения. Если реквизит пустой, Получить() вернёт Неопределено — это тоже стоит обрабатывать, особенно при массовой выгрузке.
- 1Получите ссылку на объект, содержащий хранилище значений
- 2Выберите реквизит-хранилище запросом или обратитесь через объект
- 3Вызовите метод Получить() у значения реквизита
- 4Проверьте, что результат не равен Неопределено и имеет тип ДвоичныеДанные
- 5Сохраните данные методом Записать(Путь) либо передайте дальше
- 6Проверьте, что файл создан и открывается в соответствующей программе
Передача файла на клиент через временное хранилище
В управляемых формах прямой вызов Данные.Записать() на клиенте часто невозможен или небезопасен: двоичные данные формируются на сервере, а сохранить их нужно на компьютере пользователя. Стандартный приём — поместить данные во временное хранилище формы (не путать с хранилищем значений в базе) и передать клиенту адрес.
&НаСервере
Функция ПолучитьАдресФайла(ФайлСсылка)
Данные = ФайлСсылка.Файл.Получить();
Если Данные = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
КонецФункции
&НаКлиенте
Процедура СохранитьФайл(Команда)
Адрес = ПолучитьАдресФайла(ТекущаяСсылка);
Если Адрес = Неопределено Тогда
ПоказатьПредупреждение(, "Файл отсутствует в базе");
Возврат;
КонецЕсли;
ПолучитьФайл(Адрес, "отчет.xlsx", Истина);
КонецПроцедуры
Метод ПолучитьФайл() инициирует диалог сохранения у пользователя. В веб-клиенте это будет стандартная загрузка браузера. Второй параметр ПоместитьВоВременноеХранилище() — идентификатор формы — привязывает данные к времени жизни формы, иначе они удалятся после завершения серверного вызова.
Получение файла из типовых механизмов БСП
В конфигурациях на базе Библиотеки стандартных подсистем (УТ, ERP, БП, ЗУП) файлы обычно хранятся не в самом объекте, а в справочнике присоединенных файлов, а их содержимое — в регистре сведений (например, «ДвоичныеДанныеФайлов») или в томах на диске. Напрямую лезть в эти таблицы не нужно: БСП предоставляет готовые функции.
// Получить двоичные данные присоединенного файла
Данные = РаботаСФайлами.ДвоичныеДанныеФайла(ПрисоединенныйФайл);
// Список файлов, привязанных к объекту
МассивФайлов = Новый Массив;
РаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(Владелец, МассивФайлов);
Функция РаботаСФайлами.ДвоичныеДанныеФайла() сама определяет, где лежит файл — в базе или в томе на диске, — и возвращает двоичные данные. Это правильный путь: прямое обращение к внутренним таблицам БСП ломается при обновлении конфигурации, а программный интерфейс поддерживается разработчиками библиотеки.
Точные имена функций зависят от версии БСП, встроенной в вашу конфигурацию. Актуальную сигнатуру всегда можно посмотреть в общем модуле РаботаСФайлами через конфигуратор.
Способы получения файла
Подходит для собственных реквизитов с типом ХранилищеЗначения. Полный контроль, но нужно самому обрабатывать типы и пустые значения.
Правильный способ для типовых конфигураций на БСП. Учитывает хранение в томах, но привязан к конкретной версии библиотеки.
Стандарт для передачи файла пользователю в управляемых формах и веб-клиенте. Требует разделения кода на серверную и клиентскую части.
Работа с нефайловым содержимым хранилища
Не всегда в хранилище значений кладут файл. В типовых решениях там встречаются табличные документы (макеты, сохранённые печатные формы), картинки, настройки отчётов в виде сериализованных структур. Способ извлечения тот же — Получить(), но дальнейшая обработка зависит от типа.
Данные = ОбъектСсылка.ДанныеХранилища.Получить();
Если ТипЗнч(Данные) = Тип("ТабличныйДокумент") Тогда
Данные.Записать("C:\Temp\форма.mxl");
ИначеЕсли ТипЗнч(Данные) = Тип("Картинка") Тогда
Данные.ПолучитьДвоичныеДанные().Записать("C:\Temp\image.png");
ИначеЕсли ТипЗнч(Данные) = Тип("Строка") Тогда
// Например, XML или JSON — читаем как текст
Содержимое = Данные;
КонецЕсли;
Если в хранилище помещали произвольный объект через ЗначениеВСтрокуВнутр() или сериализацию XDTO, после Получить() вы получите уже готовый объект — дополнительная десериализация не требуется, платформа выполняет её автоматически.
Типичные ошибки и их диагностика
Большинство проблем при извлечении файлов сводится к нескольким повторяющимся сценариям. Первая — результат Неопределено: реквизит не заполнен или данные были очищены регламентной операцией. Вторая — несовпадение типа: код ожидает двоичные данные, а в хранилище лежит строка или картинка. Третья — попытка записать файл в каталог, к которому у сервера 1С нет прав доступа: Записать() выполняется в контексте того процесса, где вызван, и на сервере это учётная запись агента.
Ещё одна частая ситуация — файл «извлекается», но не открывается. Причина обычно в том, что в хранилище записали не сами двоичные данные, а, например, картинку или документ другого формата, либо при записи в базу файл был повреждён обрезкой строки. Проверить можно, сравнив размер извлечённого файла с размером, указанным в реквизитах присоединенного файла.
Производительность и ограничения
Каждый вызов Получить() распаковывает данные в память. При массовой обработке — например, выгрузке всех присоединенных файлов контрагентов — это даёт серьёзную нагрузку: десятки гигабайт могут пройти через память сервера. Практические рекомендации: обрабатывайте файлы порциями, сразу записывайте результат на диск и не удерживайте массивы двоичных данных дольше необходимого.
В запросах реквизит-хранилище можно выбирать, но нельзя использовать в условиях сравнения и группировках. Если нужно отобрать только объекты с непустым хранилищем, надёжнее ориентироваться на сопутствующие признаки (например, реквизит «Размер» или «ЕстьФайл» в типовых справочниках), чем выбирать всё и проверять в цикле.
Проверка результата
После извлечения убедитесь, что файл действительно получен корректно. Минимальный набор проверок: файл существует на диске, его размер больше нуля и совпадает с ожидаемым, файл открывается штатной программой (PDF — в просмотрщике, XLSX — в Excel, картинка — в просмотрщике изображений). Для программной проверки внутри 1С удобно использовать объект Файл и его свойство Размер().
Как проверить результат
Возвращает ДвоичныеДанные или ожидаемый объект
Неопределено — реквизит пуст или данные удалены
Файл существует, размер больше нуля, открывается в нужной программе
Файл нулевого размера или программа сообщает о повреждении
ПолучитьФайл() открывает диалог сохранения и передаёт данные
Адрес пустой или данные уже удалены из временного хранилища
Частые вопросы
Что возвращает метод Получить(), если хранилище пустое?
Значение Неопределено. Поэтому перед любыми операциями с результатом добавляйте проверку: Если Данные = Неопределено Тогда ... КонецЕсли. Это особенно важно при массовой обработке, где часть объектов может не иметь файла.
Можно ли прочитать содержимое хранилища значений запросом?
Выбрать реквизит-хранилище в запросе можно, но распаковать его внутри запроса нельзя — только через Получить() в коде. Также хранилище нельзя использовать в условиях ГДЕ, соединениях и группировках.
Как получить файл, если он хранится в томе на диске, а не в базе?
В типовых конфигурациях используйте функцию РаботаСФайлами.ДвоичныеДанныеФайла() — она сама определяет место хранения. При ручной реализации нужно прочитать путь к тому из настроек и загрузить файл через объект ДвоичныеДанные с указанием пути.
Почему извлечённый файл не открывается?
Чаще всего в хранилище лежит не тот тип данных, который ожидался: например, картинка вместо двоичных данных, или файл был записан в другом формате. Проверьте тип результата через ТипЗнч() и сравните размер извлечённого файла с исходным.
Как выгрузить все присоединенные файлы объекта в папку?
Получите список присоединенных файлов через РаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(), затем в цикле для каждого вызовите ДвоичныеДанныеФайла() и сохраните результат методом Записать(), формируя имя файла из реквизитов Наименование и Расширение. Обрабатывайте файлы порциями, чтобы не перегружать память сервера.
Можно ли получить файл из хранилища в тонком или веб-клиенте без сервера?
Нет. Извлечение выполняется на сервере, после чего данные передаются клиенту через временное хранилище (ПоместитьВоВременноеХранилище) и сохраняются методом ПолучитьФайл() или НачатьПолучениеФайлов().