Разработка и Конфигурация · 11 мин
Как записать двоичные данные в файл в 1С
Как записать двоичные данные в файл в 1С: работа с объектом ДвоичныеДанные, запись из буфера, хранилища значений и Base64, примеры кода и частые ошибки.
Двоичные данные в 1С — это любые файлы, которые платформа не интерпретирует как текст: картинки, PDF-документы, архивы, выгрузки обменов, подписанные файлы ЭДО. Работа с ними строится вокруг встроенного типа ДвоичныеДанные, который умеет читать содержимое файла с диска и записывать его обратно методом Записать(). Базовый сценарий умещается в несколько строк кода, но на практике задача усложняется: данные могут приходить из хранилища значений, из буфера двоичных данных, из Base64-строки или из временного хранилища после загрузки с клиента.
Ключевой момент, который нужно понять сразу: ДвоичныеДанные — это объект-обёртка над готовым массивом байт, а не поток записи. Вы не можете «дописать» байты в файл кусками через этот объект — при вызове Записать() он целиком перезаписывает целевой файл. Для потоковой записи больших массивов или посимвольной обработки используются другие механизмы: Поток, ЗаписьДанных, ФайловыйПоток.
Второй важный нюанс — место выполнения кода. На тонком клиенте прямой доступ к файловой системе сервера невозможен: файл сначала передаётся на сервер через временное хранилище, а запись выполняется в серверной процедуре. Игнорирование этого разделения — самая частая причина ошибок «файл не найден» и «метод не обнаружен» в клиент-серверных базах.
Объект ДвоичныеДанные: базовый способ записи в файл
Самый простой сценарий — данные уже лежат в файле или получены в виде объекта ДвоичныеДанные, и их нужно сохранить по новому пути. Конструктор объекта принимает путь к существующему файлу, а метод Записать() сохраняет содержимое в указанное место.
ДвоичныеДанные = Новый ДвоичныеДанные("C:\Temp\исходный.pdf");
ДвоичныеДанные.Записать("D:\Архив\копия.pdf");Метод Записать() принимает либо строку с полным именем файла, либо объект потока. Если файл по указанному пути уже существует, он будет полностью перезаписан без предупреждения — платформа не спрашивает подтверждения и не создаёт резервную копию. Поэтому перед записью в рабочие каталоги стоит проверять существование файла через объект Файл и его метод Существует().
Каталог назначения должен существовать заранее: метод Записать() не создаёт промежуточные папки. Если путь содержит несуществующий каталог, будет вызвано исключение. Создать структуру каталогов можно функцией СоздатьКаталог(), которая отрабатывает и для вложенных путей.
Запись данных из хранилища значений и реквизитов
Типовой прикладной сценарий — файл хранится в базе в реквизите с типом ХранилищеЗначения (например, картинка номенклатуры или присоединённый файл), и его нужно выгрузить на диск. Значение извлекается методом Получить(), который возвращает именно объект ДвоичныеДанные, после чего работает тот же метод Записать().
Запрос = Новый Запрос("ВЫБРАТЬ Файл ИЗ Справочник.ПрисоединенныеФайлы ГДЕ Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", СсылкаНаФайл);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Данные = Выборка.Файл.Получить();
Если Данные <> Неопределено Тогда
Данные.Записать("C:\Temp\выгрузка.bin");
КонецЕсли;
КонецЕсли;Обязательно проверяйте результат Получить() на Неопределено: если реквизит пустой или в хранилище записано значение другого типа, попытка вызвать Записать() приведёт к ошибке. Для надёжности можно дополнительно проверить тип через ТипЗнч(Данные) = Тип(\"ДвоичныеДанные\").
Если файл хранится в типовом механизме присоединённых файлов (БСП), предпочтительнее использовать готовые функции общего модуля РаботаСФайлами — они корректно обрабатывают тома хранения, версии файлов и права доступа, чего ручной код не делает.
Запись из буфера двоичных данных и Base64
Объект БуферДвоичныхДанных позволяет собирать байты программно: записывать числа в нужном порядке байт, формировать заголовки собственных форматов, собирать пакеты для обмена с оборудованием. Готовый буфер преобразуется в двоичные данные методом ПолучитьДвоичныеДанные(), после чего записывается стандартно.
Буфер = Новый БуферДвоичныхДанных(4);
Буфер.ЗаписатьЦелое32(0, 123456, ПорядокБайтов.LittleEndian);
Данные = Буфер.ПолучитьДвоичныеДанные();
Данные.Записать("C:\Temp\packet.bin");Обратная ситуация — данные приходят извне в виде строки Base64, например из веб-сервиса или HTTP-API. Для преобразования используются функции Base64Значение() и Base64Строка(). Первая возвращает ДвоичныеДанные, готовые к записи; вторая, наоборот, кодирует двоичные данные в строку для передачи.
СтрокаBase64 = ОтветСервиса.ПолучитьТелоКакСтроку();
Данные = Base64Значение(СтрокаBase64);
Данные.Записать(КаталогВременныхФайлов() + "полученный.pdf");Запись больших файлов: потоки и ЗаписьДанных
Когда файл занимает сотни мегабайт, загрузка его целиком в память через ДвоичныеДанные может привести к переполнению памяти рабочего процесса сервера. Для таких случаев платформа предоставляет файловые потоки: ФайловыйПоток открывает файл на чтение или запись, а объект ЗаписьДанных позволяет писать в поток порциями — буферами, строками, другими потоками.
ПотокЗаписи = ФайловыеПотоки.ОткрытьДляЗаписи("D:\Big\archive.zip");
Запись = Новый ЗаписьДанных(ПотокЗаписи);
Запись.ЗаписатьБуферДвоичныхДанных(Буфер);
Запись.Закрыть();
ПотокЗаписи.Закрыть();Обязательно закрывайте потоки и объекты записи после завершения работы. Незакрытый файловый поток держит дескриптор файла: файл остаётся заблокированным для других процессов, а при массовых операциях можно исчерпать лимит открытых дескрипторов операционной системы. Безопасный шаблон — оборачивать работу в Попытка ... Исключение с закрытием потока в обеих ветках.
Сравнение способов записи
Подходит для файлов малого и среднего размера, когда данные уже есть целиком. Ограничение: весь файл в памяти, полная перезапись.
Для больших файлов и порционной записи. Требует аккуратного закрытия потоков.
Для присоединённых файлов типовых конфигураций: учитывает тома, версии и права. Не подходит для произвольных путей вне механизма.
Клиент-серверный режим: передача файла и запись на сервере
В клиент-серверной базе код, выполняющийся на клиенте, не имеет доступа к диску сервера, а серверный код не видит диск пользователя. Стандартная схема такова: на клиенте файл помещается во временное хранилище функцией НачатьПомещениеФайла() (асинхронно) или ПоместитьВоВременноеХранилище(), затем адрес хранилища передаётся в серверную процедуру, где данные извлекаются и записываются.
// На сервере
Процедура СохранитьФайлНаСервере(АдресХранилища, ИмяФайла) Экспорт
Данные = ПолучитьИзВременногоХранилища(АдресХранилища);
Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда
Данные.Записать("/var/1c/uploads/" + ИмяФайла);
КонецЕсли;
КонецПроцедурыУчитывайте права учётной записи, под которой работает сервер 1С (обычно это отдельная служебная учётная запись, а не пользователь): у неё должны быть права на запись в целевой каталог. Ошибка «Отказано в доступе» при корректном коде почти всегда означает именно проблему прав на каталог.
- 1На клиенте вызовите НачатьПомещениеФайла() и получите адрес временного хранилища.
- 2Передайте адрес и желаемое имя файла в серверную процедуру.
- 3На сервере извлеките данные через ПолучитьИзВременногоХранилища().
- 4Проверьте тип и существование целевого каталога, при необходимости создайте его.
- 5Вызовите Данные.Записать() и удалите данные из хранилища через УдалитьИзВременногоХранилища().
Проверка результата и диагностика проблем
После записи файл стоит проверить, особенно если данные прошли через несколько преобразований (Base64, буфер, хранилище). Минимальная проверка — существование файла и его размер: размер исходных данных можно узнать через метод Размер() объекта ДвоичныеДанные и сравнить с размером записанного файла через объект Файл.
Как проверить результат
Новый Файл(Путь).Существует() возвращает Истина
Файла нет — проверяйте путь, права и место выполнения кода
Размер совпадает с Данные.Размер()
Размер меньше или нулевой — данные повреждены при передаче или Base64 декодирован с ошибкой
Файл открывается штатной программой (PDF, просмотр изображений)
Программа сообщает о повреждении — вероятна запись текстовым объектом или лишний префикс в Base64
Если файл записывается, но не открывается, чаще всего виновата промежуточная текстовая обработка: чтение через ЧтениеТекста, передача через строковый реквизит без Base64, ручная конкатенация строк. Двоичные данные нельзя пропускать через строковые переменные без кодирования — любое перекодирование необратимо портит байты.
Частые вопросы
Чем ДвоичныеДанные отличаются от БуфераДвоичныхДанных?
ДвоичныеДанные — неизменяемый объект-обёртка над готовым массивом байт: его можно только прочитать из файла или записать целиком. БуферДвоичныхДанных — изменяемая структура для посимвольной сборки: в него можно писать числа, байты и фрагменты, а затем преобразовать в ДвоичныеДанные методом ПолучитьДвоичныеДанные().
Почему файл записывается, но не открывается?
Наиболее вероятные причины: данные прошли через текстовую обработку (ЧтениеТекста, строковый реквизит) и были перекодированы; Base64-строка содержала служебный префикс вида data:...;base64, который не был отрезан; или в хранилище значений лежал не файл, а другой объект, сериализованный платформой.
Как записать файл, если нужно дописать данные в конец существующего?
Метод ДвоичныеДанные.Записать() всегда перезаписывает файл целиком. Для дозаписи откройте файл через ФайловыеПотоки.Открыть() с режимом, допускающим запись, переместите позицию потока в конец и пишите через ЗаписьДанных. Либо прочитайте старое содержимое, объедините с новым в буфере и запишите заново.
Можно ли записать файл напрямую на диск пользователя из серверной процедуры?
Нет, сервер не имеет доступа к файловой системе клиента. Нужно передать данные на клиента (например, через временное хранилище), а на клиенте использовать НачатьПолучениеФайла() или диалог сохранения с последующей записью.
Что делать с ошибкой «Отказано в доступе» при записи на сервере?
Проверьте права учётной записи службы сервера 1С на целевой каталог — она отличается от учётной записи пользователя. Также убедитесь, что путь существует, файл не открыт другим процессом и не стоит атрибут «только чтение».
Как передать двоичные данные через строку, например в XML или JSON?
Используйте кодирование Base64: функция Base64Строка() преобразует двоичные данные в безопасную для текстовых форматов строку, а Base64Значение() на приёмной стороне восстанавливает исходные байты. Прямая вставка двоичных данных в текст испортит файл.
Что важно запомнить
Базовая запись — ДвоичныеДанные.Записать(Путь), но метод полностью перезаписывает файл и держит всё содержимое в памяти. В клиент-серверном режиме пишите на сервере через временное хранилище, большие файлы — через файловые потоки с обязательным закрытием, а результат проверяйте по существованию и размеру файла.