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

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

Как получить файл из двоичных данных в 1С

Как получить файл из двоичных данных в 1С: методы Записать, ПолучитьИзВременногоХранилища, Base64. Примеры кода, проверка результата и типичные ошибки.

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

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

Откуда могут приходить двоичные данные

Прежде чем писать код, определите источник данных — от этого зависит способ получения объекта ДвоичныеДанные. Сам объект универсален, но путь к нему различается.

  • ХранилищеЗначения — типовой способ хранения файлов в реквизитах справочников и регистрах сведений. Извлекается методом Получить().
  • Временное хранилище — адрес вида e1cib/tempstorage/..., в который помещаются данные при передаче между клиентом и сервером (загрузка файла, помещение картинки).
  • Строка Base64 — типичный формат передачи файлов через HTTP-сервисы, веб-сервисы и JSON.
  • Макет конфигурации с типом «Двоичные данные» — готовые файлы, зашитые в конфигурацию.
  • Поток / ПотокВПамяти — при работе с большими файлами и потоковой обработкой.

Базовый способ: метод Записать()

Если объект двоичных данных уже есть, сохранение файла занимает одну строку. Метод Записать() принимает полный путь к файлу, включая имя и расширение.

ДвоичныеДанные = Справочники.Макеты.НайтиПоКоду("Шаблон").Файл.Получить();

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

ВызватьИсключение "Двоичные данные отсутствуют в хранилище значения";

КонецЕсли;

ИмяФайла = "C:\Temp\Шаблон.docx";

ДвоичныеДанные.Записать(ИмяФайла);

Обратите внимание: расширение файла платформа не восстанавливает автоматически. Если в хранилище лежит PDF, а вы записали его с расширением .txt, файл откроется некорректно. Расширение нужно хранить отдельно (в типовых конфигурациях для этого есть реквизит «Расширение» присоединённого файла) или определять по сигнатуре первых байт.

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

ИмяФайла = ПолучитьИмяВременногоФайла("pdf");

ДвоичныеДанные.Записать(ИмяФайла);

Получение данных из хранилища значений

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

Запрос = Новый Запрос(

"ВЫБРАТЬ

| Номенклатура.Ссылка,

| Номенклатура.ФайлКартинки

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ЭтоГруппа");

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

ДД = Выборка.ФайлКартинки.Получить();

Если ТипЗнч(ДД) = Тип("ДвоичныеДанные") Тогда

ДД.Записать("C:\Images\" + Строка(Выборка.Ссылка.УникальныйИдентификатор()) + ".jpg");

КонецЕсли;

КонецЦикла;

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

Порядок действий
  1. 1
    Определите источник данных: хранилище значения, временное хранилище, Base64 или макет
  2. 2
    Получите объект ДвоичныеДанные подходящим методом
  3. 3
    Проверьте, что полученное значение имеет тип ДвоичныеДанные
  4. 4
    Сформируйте полное имя файла с правильным расширением
  5. 5
    Вызовите Записать(ИмяФайла)
  6. 6
    Проверьте размер файла и его открытие в целевой программе

Работа с временным хранилищем

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

&НаКлиенте

Процедура ЗагрузитьФайл(Команда)

НачатьПомещениеФайла(

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

, , Истина, УникальныйИдентификатор);

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

&НаСервере

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

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

ДД.Записать("C:\Temp\received.bin");

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

Обратная задача — отдать файл на клиент: поместите двоичные данные в хранилище через ПоместитьВоВременноеХранилище(ДД, УникальныйИдентификатор), а на клиенте используйте ПолучитьФайл() или НачатьПолучениеФайлов(). Для работы с файловой системой на тонком клиенте требуется расширение работы с файлами — без него методы записи на диск будут недоступны.

Двоичные данные из строки Base64

При обмене через HTTP и веб-сервисы файлы почти всегда передаются в кодировке Base64. Платформа предоставляет пару функций Base64Значение() и Base64Строка():

// Строка Base64 из тела HTTP-ответа или JSON

ДД = Base64Значение(СтрокаBase64);

ДД.Записать("C:\Temp\document.pdf");

// Обратное преобразование — файл в Base64 для отправки

ДД = Новый ДвоичныеДанные("C:\Temp\document.pdf");

СтрокаBase64 = Base64Строка(ДД);

Если Base64Значение() возвращает Неопределено, значит строка повреждена: потеряны символы, добавлены переносы в неправильных местах или данные обрезаны при чтении JSON. Проверьте длину строки и первые символы до преобразования.

Большие файлы и потоки

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

Поток = ФайловыеПотоки.ОткрытьДляЗаписи("C:\Temp\big.zip");

ПотокИсточника.КопироватьВ(Поток);

Поток.Закрыть();

Потоковый подход также позволяет писать файл частями по мере получения данных из HTTP-ответа, не держа весь объём в памяти. Для типовых задач размером в несколько мегабайт обычного Записать() достаточно.

Проверка результата и типичные ошибки

После записи убедитесь, что файл корректен. Минимальная проверка — существование и ненулевой размер:

Файл = Новый Файл(ИмяФайла);

Если Не Файл.Существует() Или Файл.Размер() = 0 Тогда

ВызватьИсключение "Файл не записан или пуст";

КонецЕсли;

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

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

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

Существование и размер файла
Норма

Файл есть, размер больше 0 и равен размеру двоичных данных

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

Файл отсутствует или размер 0 байт

Открытие в целевой программе
Норма

Документ/картинка/архив открывается без ошибок

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

Программа сообщает о повреждении или неверном формате

Первые байты (сигнатура)
Норма

PDF начинается с %PDF, ZIP — с PK, JPEG — с FF D8

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

В начале виден текст Base64 или мусор

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

Как узнать расширение файла, если сохранены только двоичные данные?

По сигнатуре первых байт: PDF начинается с «%PDF», ZIP и DOCX/XLSX — с «PK», PNG — с байтов 89 50 4E 47, JPEG — с FF D8. Прочитайте начало данных и сопоставьте с известными сигнатурами. Надёжнее — хранить расширение отдельно при загрузке файла.

Метод Записать() выдаёт ошибку «Ошибка доступа к файлу». Что делать?

Проверьте, существует ли каталог, есть ли у учётной записи сервера 1С права на запись в него и не открыт ли файл другой программой. На сервере под Linux проверьте владельца каталога и права пользователя, под которым работает агент сервера.

Как получить файл из присоединённых файлов в типовой конфигурации?

В конфигурациях на БСП используйте функцию общего модуля РаботаСФайлами: она возвращает двоичные данные присоединённого файла по ссылке. Дальше применяется обычный Записать(). Прямой запрос к реквизиту хранения обходите, если доступен программный интерфейс БСП.

Можно ли записать файл на клиенте без модального окна сохранения?

Да, через ПолучитьФайл(АдресХранилища, ИмяФайла, Ложь) — третий параметр отключает диалог. Требуется расширение работы с файлами и разрешение пользователя на доступ к файловой системе в браузере или тонком клиенте.

Base64Значение() вернуло Неопределено. В чём причина?

Строка не является корректным Base64: лишние пробелы, переносы, обрезанный хвост или префикс вида «data:image/png;base64,». Удалите префикс до запятой и лишние символы, затем повторите преобразование.

Как выгрузить много файлов пакетно, не перегружая сервер?

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

Итог

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

Получение файла из двоичных данных сводится к трём шагам: получить объект ДвоичныеДанные подходящим способом (Получить, ПолучитьИзВременногоХранилища, Base64Значение), вызвать Записать() с корректным путём и расширением, затем проверить размер и открытие файла. Большинство проблем связаны с пустым хранилищем, неверным расширением и неправильной обработкой Base64.