Разработка и Конфигурация · 12 мин
Как прочитать двоичные данные в 1С
Как прочитать двоичные данные в 1С: объект ЧтениеДанных, работа с буфером, потоками и файлами. Примеры кода, типичные ошибки и проверка результата.
Двоичные данные в 1С встречаются повсюду: картинки в справочниках, файлы во вложениях, ответы HTTP-сервисов, архивы обменов, подписанные документы. Чтобы извлечь из них информацию — текст, числа, структуру файла — недостаточно просто получить объект ДвоичныеДанные: нужно понимать, как устроены потоки, буферы и механизм последовательного чтения.
Платформа 1С:Предприятие 8.3 предоставляет для этого встроенный объект ЧтениеДанных, который позволяет читать байты, целые числа разной разрядности, строки и отдельные фрагменты из файла или потока. Дополнительно используются объекты Поток, БуферДвоичныхДанных и классические методы ПолучитьИмяВременногоФайла и Записать.
Ниже разобраны основные сценарии: чтение из файла на диске, из хранилища значения, из HTTP-ответа, посимвольный разбор заголовка файла и типичные ошибки, из-за которых данные читаются «криво» или не читаются вовсе.
Что такое двоичные данные в 1С и какие объекты с ними работают
Объект ДвоичныеДанные — это неизменяемый набор байтов. Его можно получить из файла (Новый ДвоичныеДанные(ПутьКФайлу)), из хранилища значения, из HTTP-ответа или из base64-строки. Сам по себе он не даёт инструментов разбора: у него есть только методы Размер() и Записать().
Для пословного разбора содержимого служат три связанных механизма:
ЧтениеДанных— последовательное чтение чисел, строк и блоков байтов из файла или потока;Поток/ПотокВПамяти/ФайловыйПоток— универсальное представление источника данных с возможностью чтения и записи;БуферДвоичныхДанных— изменяемый массив байтов с прямым доступом по индексу и указанием порядка байтов.
Выбор инструмента зависит от задачи: если нужно просто переслать или сохранить файл — достаточно ДвоичныеДанные; если нужно разобрать внутреннюю структуру (заголовок, смещения, длины блоков) — потребуется ЧтениеДанных с буфером.
Как получить двоичные данные из файла, хранилища и HTTP
Самый частый источник — файл на диске. Конструктор принимает полный путь и загружает содержимое целиком в память:
ДвоичныеДанные = Новый ДвоичныеДанные("C:\Data\picture.png");
РазмерФайла = ДвоичныеДанные.Размер();
Из хранилища значения (например, реквизит справочника с типом ХранилищеЗначения) данные извлекаются методом Получить():
Данные = ЭлементСправочника.ФайлДанных.Получить();
Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда
Данные.Записать("C:\Temp\extracted.bin");
КонецЕсли;
Из HTTP-ответа двоичное тело получают методом ПолучитьТелоКакДвоичныеДанные() объекта HTTPОтвет. Это правильный способ для картинок, архивов и PDF — использование ПолучитьТелоКакСтроку() для бинарных ответов испортит данные из-за перекодировки.
Чтение через объект ЧтениеДанных: базовый сценарий
Объект ЧтениеДанных создаётся для файла, потока или объекта ДвоичныеДанные. После открытия доступен указатель текущей позиции (ТекущаяПозиция()), и каждый вызов чтения сдвигает его вперёд.
Чтение = Новый ЧтениеДанных("C:\Data\file.dat");
МагическоеЧисло = Чтение.ПрочитатьЦелое32(); // 4 байта
ДлинаБлока = Чтение.ПрочитатьЦелое16(); // 2 байта
СтрокаИмя = Чтение.ПрочитатьСимволы(8); // 8 символов
Чтение.Закрыть();
Основные методы чтения:
ПрочитатьБайт()— один байт как число 0–255;ПрочитатьЦелое16(),ПрочитатьЦелое32(),ПрочитатьЦелое64()— целые числа, по умолчанию в порядке LittleEndian;ПрочитатьСимволы(Количество)— строка указанной длины;ПрочитатьВБуферДвоичныхДанных(Буфер, Позиция, Количество)— блок байтов в буфер;Пропустить(КоличествоБайт)— сдвиг позиции без чтения.
Порядок байтов задаётся либо в конструкторе (Новый ЧтениеДанных(Источник, ПорядокБайтов.BigEndian)), либо свойством ПорядокБайтов до начала чтения. Проверить достижение конца источника можно через ЧтениеЗавершено или сравнением текущей позиции с размером источника.
Чтение = Новый ЧтениеДанных(ПутьКФайлу);
Пока Не Чтение.ЧтениеЗавершено Цикл
Байт = Чтение.ПрочитатьБайт();
КонецЦикла;
Чтение.Закрыть();Работа с потоками и буфером двоичных данных
Когда источник — не файл, а данные в памяти или часть другого потока, удобнее работать через Поток. Из объекта ДвоичныеДанные поток открывается методом ОткрытьПотокДляЧтения(), а для сборки данных в памяти используется ПотокВПамяти.
Поток = ДвоичныеДанные.ОткрытьПотокДляЧтения();
Чтение = Новый ЧтениеДанных(Поток);
Буфер = Новый БуферДвоичныхДанных(16);
Чтение.ПрочитатьВБуферДвоичныхДанных(Буфер);
ПервыйБайт = Буфер[0];
Чтение.Закрыть();
Буфер полезен, когда нужно прочитать блок байтов и затем интерпретировать его по-разному: как массив байтов, как числа с разным порядком следования, как подстроки. У буфера можно указать собственный порядок байтов, отличный от порядка чтения, — это упрощает разбор смешанных форматов.
Для чтения части большого файла без загрузки целиком применяется ФайловыйПоток с установкой позиции через Перейти(Смещение, ПозицияВПотоке.Начало). Это стандартный приём при разборе форматов, где в заголовке указаны смещения блоков данных.
Распространённые ошибки и как их избежать
Большинство проблем при чтении двоичных данных связано не с синтаксисом, а с неверными предположениями о формате источника. Ниже — типичные ситуации.
Отдельная группа ошибок — кодировки строк. Метод ПрочитатьСимволы по умолчанию интерпретирует байты в кодировке UTF-8. Если строка в файле записана в ANSI (Windows-1251) или UTF-16, результат будет искажён. Кодировку задают параметром конструктора или свойством КодировкаТекста до чтения.
Ещё одна ловушка — чтение на клиенте в веб-клиенте или тонком клиенте без доступа к файловой системе сервера. Конструктор Новый ДвоичныеДанные(Путь) ищет файл на той стороне, где выполняется код: в серверной процедуре путь клиентской машины недоступен. Файл нужно сначала передать на сервер через ПоместитьВоВременноеХранилище или механизм НачатьПомещениеФайла.
Как проверить, что данные прочитаны правильно
Надёжный способ верификации — сравнение контрольных признаков формата. У большинства форматов файлов первые байты образуют сигнатуру: у PNG это последовательность 89 50 4E 47, у ZIP — 50 4B 03 04, у PDF — строка %PDF. Прочитайте первые байты и сравните с ожидаемыми: если сигнатура не совпадает, источник повреждён или это не тот формат.
Как проверить результат
Совпадает с известной сигнатурой формата
Другие байты — источник повреждён или формат иной
Сумма прочитанных блоков равна размеру источника
Расхождение — где-то пропущены или лишне прочитаны байты
Файл после Записать() открывается штатной программой
Ошибка открытия — данные испорчены при получении или записи
Длины и смещения не превышают размер файла
Огромные значения — неверный порядок байтов или смещение чтения
Для отладки полезно выводить прочитанные байты в шестнадцатеричном виде и сверять с дампом файла в любом hex-редакторе. Если структура разбирается циклично (блок «длина + данные»), добавьте проверку, что прочитанная длина не превышает остаток источника, — это защитит от бесконечного цикла на испорченных данных.
- 1Откройте файл в hex-редакторе и определите сигнатуру и структуру заголовка.
- 2Создайте ЧтениеДанных с нужным порядком байтов и кодировкой.
- 3Прочитайте и проверьте сигнатуру — при несовпадении прекратите разбор.
- 4Последовательно читайте поля, контролируя текущую позицию после каждого шага.
- 5Проверьте, что суммарно прочитан весь источник, и закройте чтение.
Когда разбор не нужен: передача и сохранение как есть
Во многих прикладных задачах разбирать содержимое не требуется: файл нужно просто сохранить в базу, отправить по HTTP или приложить к письму. В этом случае работайте с ДвоичныеДанные как с «чёрным ящиком»: получили — записали методом Записать(Путь) или поместили в хранилище значения.
Для передачи через текстовые протоколы (JSON, XML) двоичные данные кодируют в base64 функциями Base64Строка() и Base64Значение(). Учтите, что base64 увеличивает объём примерно на треть — для больших файлов это заметно влияет на трафик и время обмена.
Как выбрать действие
Что важно запомнить
ДвоичныеДанные — контейнер байтов без средств разбора; для разбора служит ЧтениеДанных с методами чтения чисел, строк и буферов. Контролируйте порядок байтов, кодировку, текущую позицию и не загружайте большие файлы целиком в память. Перед разбором проверяйте сигнатуру формата, после — открываемость результата.
Частые вопросы
Чем ЧтениеДанных отличается от ЧтениеТекста?
ЧтениеТекста интерпретирует содержимое файла как текст в заданной кодировке и читает построчно или целиком. ЧтениеДанных работает на уровне байтов и позволяет читать числа заданной разрядности, отдельные байты и произвольные блоки. Для бинарных форматов (картинки, архивы, проприетарные файлы) подходит только ЧтениеДанных.
Как прочитать двоичные данные из макета конфигурации?
Если макет имеет тип «Двоичные данные», используйте ПолучитьМакет("ИмяМакета") — результатом будет объект ДвоичныеДанные. Дальше его можно записать в файл методом Записать или открыть поток для разбора через ОткрытьПотокДляЧтения.
Можно ли читать файл частями, не загружая его целиком?
Да. Откройте ФайловыйПоток методом ФайловыеПотоки.ОткрытьДляЧтения(Путь), затем создайте ЧтениеДанных для этого потока и читайте блоками фиксированного размера в цикле. Позицию внутри файла задают методом Перейти с указанием смещения.
Почему прочитанные числа выглядят бессмысленно большими?
Чаще всего причина в неверном порядке байтов: данные записаны в BigEndian, а читаются в LittleEndian (или наоборот). Задайте свойство ПорядокБайтов объекта ЧтениеДанных в соответствии с форматом источника и перечитайте значения. Вторая возможная причина — сбитая позиция чтения из-за ошибки в длине предыдущего поля.
Как сохранить картинку из базы на диск?
Получите значение из реквизита типа ХранилищеЗначения методом Получить(), проверьте, что тип результата — ДвоичныеДанные, и вызовите метод Записать с полным путём, включая правильное расширение файла. Если расширение неизвестно, определите формат по сигнатуре первых байтов.
Работает ли ЧтениеДанных на клиенте и в веб-клиенте?
Объект доступен и на клиенте, и на сервере, но файловые операции выполняются на той стороне, где исполняется код. В веб-клиенте прямой доступ к диску пользователя ограничен: файл сначала помещают во временное хранилище через асинхронные методы помещения файлов, а разбор выполняют на сервере.