При переходе от использования временных файлов к работе с потоками в памяти (ПотокВПамяти) программисты часто сталкиваются с неожиданным поведением системы: двоичные данные, полученные из файла и из потока, могут различаться на несколько байтов. Чаще всего «лишними» оказываются первые три байта. В этой статье мы подробно разберем, почему это происходит, что такое маркер BOM, и как правильно управлять процессом записи текста в 1С:Предприятие.
Рассмотрим стандартную ситуацию. У нас есть задача — сформировать строку (например, для заголовка авторизации или тела POST-запроса) и преобразовать ее в двоичные данные. Традиционный способ через временный файл выглядит так:
ВременныйФайл = ПолучитьИмяВременногоФайла();
Запись = Новый ЗаписьТекста(ВременныйФайл, "UTF-8");
Запись.Записать(СтрокаДанных);
Запись.Закрыть();
ДД_Файл = Новый ДвоичныеДанные(ВременныйФайл);
Попытка переписать этот код с использованием ПотокВПамяти часто приводит к следующему результату:
ПотокДанных = Новый ПотокВПамяти();
ЗаписьТекста = Новый ЗаписьТекста(ПотокДанных, "UTF-8");
ЗаписьТекста.Записать(СтрокаДанных);
ЗаписьТекста.Закрыть();
ДД_Поток = ПотокДанных.ЗакрытьИПолучитьДвоичныеДанные();
При сравнении ДД_Файл и ДД_Поток выясняется, что данные из файла длиннее на 3 байта. Эти байты — EF BB BF в шестнадцатеричном представлении. Проанализируем ситуацию и выясним, что это маркер последовательности байтов (Byte Order Mark, сокращенно BOM) для кодировки UTF-8.
Главная причина кроется в архитектуре платформы 1С. Объект ЗаписьТекста ведет себя по-разному в зависимости от того, куда он пишет данные. Проанализируем параметры конструктора:
ТипРазделителяСтрок. Возможности явно указать «не использовать BOM» в этом конструкторе просто не существует. Платформа 1С по умолчанию всегда добавляет BOM при создании текстового файла в кодировке UTF-8.ИспользоватьBOM.Посмотрим на пример правильной инициализации записи в поток, если нам нужно полное соответствие файловому методу (с добавлением BOM):
// Пятый параметр - Истина (использовать BOM)
ЗаписьТекста = Новый ЗаписьТекста(ПотокДанных, КодировкаТекста.UTF8, , , Истина);
Если же мы, наоборот, хотим избавиться от BOM (что критично для большинства веб-сервисов и HTTP-запросов), следует передавать Ложь. По умолчанию при работе с потоком 1С часто не добавляет маркер, что и создает разницу с файловым методом.
Начиная с версии платформы 8.3.10, существует гораздо более изящный способ преобразования текста в двоичные данные, который позволяет избежать создания потоков и объектов записи вручную. Разберем этот метод:
// Синтаксис: ПолучитьДвоичныеДанныеИзСтроки(<Строка>, <Кодировка>, <ИспользоватьBOM>)
ДД = ПолучитьДвоичныеДанныеИзСтроки(СтрокаДанных, КодировкаТекста.UTF8, Ложь);
Этот метод является предпочтительным, так как он:
При работе с объектами ЗаписьТекста и ПотокВПамяти крайне важно соблюдать последовательность закрытия объектов. Проанализируем, что происходит «под капотом»:
Объект ЗаписьТекста использует внутренний буфер для оптимизации работы. Если мы попытаемся получить данные из потока до того, как вызвали метод Закрыть() у объекта записи, мы рискуем получить неполные данные или пустой поток, так как часть информации еще находится в буфере.
Рассмотрим правильную последовательность действий:
ПотокВПамяти.ЗаписьТекста, связанную с этим потоком.ЗаписьТекста.Закрыть(). Это «сбрасывает» буфер в поток и закрывает объект записи.ПотокДанных.ЗакрытьИПолучитьДвоичныеДанные() для получения итогового результата.Выясним, зачем вообще нужно отключать BOM. В мире Windows маркер EF BB BF часто используется текстовыми редакторами (например, Блокнотом) для распознавания кодировки. Однако в веб-разработке и при передаче данных по протоколу HTTP наличие BOM в теле запроса (особенно в JSON или XML) часто считается ошибкой. Сервер может выдать ошибку «Unexpected character» (неожиданный символ), так как он ожидает увидеть в начале данных фигурную скобку { или тег <, а не служебные байты маркера кодировки.
Поэтому при формировании тела POST-запроса в 1С через потоки всегда проверяйте, требуется ли вашему контрагенту маркер BOM. В 90% случаев его следует отключать.
Подведем итог нашему анализу и сравним три способа получения двоичных данных из текста:
Используя эти знания, мы можем эффективно управлять форматом данных и избегать трудноуловимых ошибок при интеграции 1С с внешними системами.