Разработка и Конфигурация · 12 мин
Как сохранить файл из хранилища значений на диск в 1С
Как сохранить файл из хранилища значений в 1С на диск: метод Получить(), ДвоичныеДанные, запись через Записать(), примеры кода, типичные ошибки и проверка результата.
В типовых и самописных конфигурациях 1С файлы — картинки, печатные формы, вложения писем, выгрузки — часто хранятся в реквизитах с типом «ХранилищеЗначения». Внутри такого реквизита лежат двоичные данные, и чтобы получить файл обратно на диск, нужно последовательно извлечь значение из хранилища и записать его в файловую систему. Операция выполняется штатными средствами встроенного языка и не требует внешних компонент.
Типичная цепочка выглядит так: прочитать реквизит объекта, вызвать метод Получить(), убедиться, что результат имеет тип ДвоичныеДанные, и записать его методом Записать() по нужному пути. Трудности обычно возникают из-за того, что в хранилище могут быть упакованы не только двоичные данные, но и структуры, строки или значение Неопределено, а также из-за различий между тонким клиентом, веб-клиентом и сервером.
Ниже разобран рабочий код для сервера и клиента, способы определить расширение файла, вариант с временным хранилищем для веб-клиента, проверка результата и типичные ошибки, из-за которых файл сохраняется пустым или не сохраняется вовсе.
Как устроено хранилище значений и что в нём может лежать
Реквизит типа «ХранилищеЗначения» — это контейнер, в который платформа упаковывает произвольное значение: двоичные данные, строку, картинку, структуру, таблицу значений и даже сериализуемые объекты. Перед записью значение помещается конструктором Новый ХранилищеЗначения(Значение), а при чтении извлекается методом Получить(). Пока вы не вызвали Получить(), вы не знаете, что реально лежит внутри.
Для файлов корректное содержимое — значение типа ДвоичныеДанные. Именно у этого типа есть метод Записать(), который создаёт файл на диске. Если в хранилище положили строку с путём к файлу, картинку или результат сериализации, прямая запись не сработает: потребуется промежуточное преобразование. Поэтому первый шаг любой выгрузки — проверка типа извлечённого значения через ТипЗнч().
Отдельный случай — пустое хранилище. Если файл никогда не загружался или был очищен регламентной обработкой, Получить() вернёт Неопределено. Попытка вызвать Записать() у такого значения приведёт к ошибке выполнения, поэтому проверка на Неопределено обязательна в любом прикладном коде.
Базовый код: извлечь двоичные данные и записать файл
Минимальный рабочий фрагмент для серверной процедуры выглядит так. Сначала получаем объект (например, элемент справочника с присоединёнными файлами или документ с реквизитом «ДанныеФайла»), читаем хранилище и записываем содержимое по указанному пути:
Объект = СсылкаНаОбъект.ПолучитьОбъект();
Значение = Объект.ДанныеФайла.Получить();
Если Значение = Неопределено Тогда
ВызватьИсключение "Хранилище пустое, файл не загружен";
КонецЕсли;
Если ТипЗнч(Значение) <> Тип("ДвоичныеДанные") Тогда
ВызватьИсключение "В хранилище не двоичные данные: " + ТипЗнч(Значение);
КонецЕсли;
Значение.Записать("C:\Temp\Выгрузка.pdf");
Метод Записать() создаёт файл и перезаписывает его, если файл с таким именем уже существует. Каталог по указанному пути должен существовать заранее — платформа не создаёт вложенные папки автоматически. Если каталога нет, будет вызвано исключение, поэтому перед записью полезно проверить каталог через объект Файл и при необходимости создать его методом СоздатьКаталог().
Если в хранилище лежит значение типа Картинка, у него есть собственный метод Записать(ИмяФайла), который сохраняет изображение в исходном формате. Для строки с текстом (например, XML или CSV) используйте ТекстовыйДокумент с явным указанием кодировки, иначе кириллица может сохраниться в неправильной кодировке.
- 1Получите объект и прочитайте реквизит с хранилищем значений
- 2Вызовите метод Получить() и проверьте результат на Неопределено
- 3Убедитесь, что тип значения — ДвоичныеДанные
- 4Проверьте или создайте каталог назначения
- 5Вызовите Записать() с полным путём и именем файла
- 6Откройте файл и убедитесь, что он читается и имеет ненулевой размер
Где выполнять код: сервер, толстый и тонкий клиент
Место выполнения кода определяет, на чьём диске окажется файл. В серверной процедуре Записать() создаст файл на диске сервера 1С, а не на компьютере пользователя. Это частая причина «пропавших» файлов: обработка отработала без ошибок, а файл лежит в каталоге на сервере, куда у пользователя нет доступа.
Чтобы сохранить файл именно на компьютер пользователя в тонком клиенте, данные нужно передать с сервера. Стандартный приём — поместить двоичные данные во временное хранилище методом ПоместитьВоВременноеХранилище() в серверной процедуре, а на клиенте получить их по адресу и записать. В тонком клиенте доступна запись двоичных данных на диск, если у пользователя есть права на файловые операции.
&НаСервере
Функция ПолучитьАдресДанных(Ссылка)
Данные = Ссылка.ДанныеФайла.Получить();
Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);
КонецФункции
&НаКлиенте
Процедура СохранитьНаДиск(Команда)
Адрес = ПолучитьАдресДанных(Объект.Ссылка);
Данные = ПолучитьИзВременногоХранилища(Адрес);
Данные.Записать("C:\Users\User\Documents\Файл.pdf");
КонецПроцедуры
В веб-клиенте прямая запись по произвольному пути недоступна: браузер не даёт коду работать с файловой системой напрямую. Там используется механизм получения файла через ПолучитьФайл() или НачатьПолучениеФайлов(), который инициирует скачивание через браузер, либо расширение для работы с файлами. Учитывайте это при проектировании обработок, которые должны работать во всех режимах.
Как определить имя и расширение файла
Хранилище значений не хранит имя файла — только содержимое. Имя и расширение обычно лежат в соседних реквизитах объекта: в типовых конфигурациях это поля вроде «ИмяФайла», «Расширение», «Наименование» справочника присоединённых файлов. Перед записью соберите полное имя из этих данных и очистите его от недопустимых для файловой системы символов.
Если реквизита с расширением нет, расширение иногда можно определить по сигнатуре (первым байтам) двоичных данных: PDF начинается с %PDF, ZIP-архивы и документы Office — с PK, JPEG — с байтов FF D8. Это эвристика, а не гарантия, поэтому полагаться на неё стоит только как на запасной вариант. Надёжнее при загрузке файлов в базу всегда сохранять исходное имя в отдельном реквизите.
При формировании имени удалите или замените символы \ / : * ? " < > | — они запрещены в Windows и вызовут ошибку записи. Также следите за длиной полного пути: при очень длинных именах и глубокой вложенности каталогов запись может завершиться ошибкой из-за ограничения длины пути в файловой системе.
Массовая выгрузка файлов из базы
Когда нужно выгрузить не один файл, а все вложения справочника или документов за период, код оборачивается в цикл по выборке. Ключевые правила для массовой операции: формируйте уникальные имена файлов (например, добавляя идентификатор объекта), чтобы файлы не перезаписывали друг друга, и собирайте статистику — сколько выгружено, сколько пропущено из-за пустых хранилищ.
Для больших объёмов учитывайте, что метод Получить() загружает всё содержимое хранилища в память. При выгрузке тысяч крупных файлов имеет смысл обрабатывать данные порциями и периодически освобождать переменные. В файловом режиме работы дополнительно проверьте свободное место на диске назначения — вложения суммарно могут занимать заметный объём.
Полезно вести журнал выгрузки: записывать в табличный документ или текстовый файл соответствие «ссылка — путь к файлу — результат». Это позволит после завершения быстро найти объекты, где выгрузка не удалась, и повторить операцию точечно, а не запускать весь процесс заново.
Перед массовой выгрузкой сделайте пробный прогон на 5–10 объектах и откройте полученные файлы вручную. Это дешёвый способ поймать ошибки в именах, расширениях и правах доступа до того, как обработана вся база.
Проверка результата и безопасность данных
После записи убедитесь, что файл действительно корректен. Минимальная проверка — объект Файл: существует ли файл и каков его размер. Нулевой размер означает, что в хранилище лежали пустые двоичные данные. Для критичных выгрузок можно сравнить размер записанного файла с размером двоичных данных, полученным методом Размер(), — они должны совпадать.
Финальная проверка — открытие файла штатной программой: PDF — в просмотрщике, картинка — в редакторе, архив — в архиваторе. Если файл не открывается, хотя размер ненулевой, вероятно, в хранилище лежат данные в другом формате, чем предполагалось, или файл был повреждён ещё при загрузке в базу.
По безопасности: запись файла — операция необратимая только в части перезаписи существующего файла с тем же именем, поэтому не указывайте в качестве пути системные каталоги и файлы, которые нельзя потерять. В клиент-серверном режиме у учётной записи агента сервера 1С должны быть права на запись в целевой каталог — их отсутствие является одной из самых частых причин ошибок при серверной записи.
Как проверить результат
Файл на месте, размер больше нуля
Файла нет или размер 0 байт
Значения совпадают
Размеры различаются — запись неполная
Файл открывается и отображается корректно
Ошибка открытия или «формат не поддерживается»
Совпадает с реальным форматом содержимого
Расширение не соответствует содержимому
Частые вопросы
Метод Получить() вернул Неопределено. Что это значит?
Хранилище пустое: файл в объект не загружали либо значение было очищено. Проверьте объект в режиме предприятия и убедитесь, что вы читаете тот реквизит и ту версию объекта, где файл реально есть. В коде такие случаи обрабатывайте веткой пропуска, а не исключением.
Как сохранить файл из хранилища в веб-клиенте?
Прямая запись по пути в веб-клиенте недоступна. Поместите двоичные данные во временное хранилище на сервере, а на клиенте используйте ПолучитьФайл() или асинхронный НачатьПолучениеФайлов() — браузер инициирует скачивание, и пользователь сам выберет папку сохранения.
Файл записывается, но не открывается. В чём причина?
Чаще всего не совпадает расширение и реальный формат: например, в хранилище лежит PNG, а файл записан как .jpg. Проверьте реквизит с исходным расширением или сигнатуру данных. Вторая причина — в хранилище лежит не файл, а сериализованное значение, и его нужно преобразовать перед записью.
Можно ли сохранить файл без кода, штатными средствами?
Да, если файл хранится в справочнике присоединённых файлов типовой конфигурации: откройте карточку файла и используйте команду «Сохранить как» или открытие с последующим сохранением из программы. Код нужен, когда файлы лежат в произвольных реквизитах типа «ХранилищеЗначения» или требуется массовая выгрузка.
Где искать файл, если запись выполнялась на сервере?
На диске сервера 1С по тому пути, который был указан в методе Записать(), с учётом прав учётной записи агента сервера. Если путь был относительным, файл окажется в рабочем каталоге серверного процесса — поэтому всегда указывайте абсолютный путь.
Как выгрузить файлы из всех элементов справочника разом?
Напишите серверную процедуру с запросом по справочнику, в цикле извлекайте хранилище методом Получить(), формируйте уникальное имя (например, из GUID ссылки) и записывайте методом Записать(). Ведите журнал успешных и пропущенных объектов, чтобы повторно обработать только ошибочные.
Что важно запомнить
Файл из хранилища значений извлекается методом Получить() и записывается методом Записать() у двоичных данных. Всегда проверяйте результат на Неопределено и тип значения, помните, что серверная запись создаёт файл на сервере, а имя и расширение берите из реквизитов объекта. После записи проверяйте размер файла и его открытие в штатной программе.