Как правильно записать текст в ПотокВПамяти и избежать проблем с BOM

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При переходе от использования временных файлов к работе с потоками в памяти (ПотокВПамяти) программисты часто сталкиваются с неожиданным поведением системы: двоичные данные, полученные из файла и из потока, могут различаться на несколько байтов. Чаще всего «лишними» оказываются первые три байта. В этой статье мы подробно разберем, почему это происходит, что такое маркер BOM, и как правильно управлять процессом записи текста в 1С:Предприятие.

Суть проблемы: куда исчезают или откуда берутся 3 байта?

Рассмотрим стандартную ситуацию. У нас есть задача — сформировать строку (например, для заголовка авторизации или тела POST-запроса) и преобразовать ее в двоичные данные. Традиционный способ через временный файл выглядит так:


ВременныйФайл = ПолучитьИмяВременногоФайла();
Запись = Новый ЗаписьТекста(ВременныйФайл, "UTF-8");
Запись.Записать(СтрокаДанных);
Запись.Закрыть();
ДД_Файл = Новый ДвоичныеДанные(ВременныйФайл);

Попытка переписать этот код с использованием ПотокВПамяти часто приводит к следующему результату:


ПотокДанных = Новый ПотокВПамяти();
ЗаписьТекста = Новый ЗаписьТекста(ПотокДанных, "UTF-8");
ЗаписьТекста.Записать(СтрокаДанных);
ЗаписьТекста.Закрыть();
ДД_Поток = ПотокДанных.ЗакрытьИПолучитьДвоичныеДанные();

При сравнении ДД_Файл и ДД_Поток выясняется, что данные из файла длиннее на 3 байта. Эти байты — EF BB BF в шестнадцатеричном представлении. Проанализируем ситуацию и выясним, что это маркер последовательности байтов (Byte Order Mark, сокращенно BOM) для кодировки UTF-8.

Различие в конструкторах объекта ЗаписьТекста

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

  1. При записи в файл: Пятый параметр конструктора отвечает за ТипРазделителяСтрок. Возможности явно указать «не использовать BOM» в этом конструкторе просто не существует. Платформа 1С по умолчанию всегда добавляет BOM при создании текстового файла в кодировке UTF-8.
  2. При записи в поток: Конструктор имеет иную сигнатуру. Пятый параметр здесь — это булево значение ИспользоватьBOM.

Посмотрим на пример правильной инициализации записи в поток, если нам нужно полное соответствие файловому методу (с добавлением BOM):


// Пятый параметр - Истина (использовать BOM)
ЗаписьТекста = Новый ЗаписьТекста(ПотокДанных, КодировкаТекста.UTF8, , , Истина);

Если же мы, наоборот, хотим избавиться от BOM (что критично для большинства веб-сервисов и HTTP-запросов), следует передавать Ложь. По умолчанию при работе с потоком 1С часто не добавляет маркер, что и создает разницу с файловым методом.

Современный подход: использование ПолучитьДвоичныеДанныеИзСтроки

Начиная с версии платформы 8.3.10, существует гораздо более изящный способ преобразования текста в двоичные данные, который позволяет избежать создания потоков и объектов записи вручную. Разберем этот метод:


// Синтаксис: ПолучитьДвоичныеДанныеИзСтроки(<Строка>, <Кодировка>, <ИспользоватьBOM>)
ДД = ПолучитьДвоичныеДанныеИзСтроки(СтрокаДанных, КодировкаТекста.UTF8, Ложь);

Этот метод является предпочтительным, так как он:

Важность закрытия потоков и буферизация

При работе с объектами ЗаписьТекста и ПотокВПамяти крайне важно соблюдать последовательность закрытия объектов. Проанализируем, что происходит «под капотом»:

Объект ЗаписьТекста использует внутренний буфер для оптимизации работы. Если мы попытаемся получить данные из потока до того, как вызвали метод Закрыть() у объекта записи, мы рискуем получить неполные данные или пустой поток, так как часть информации еще находится в буфере.

Рассмотрим правильную последовательность действий:

  1. Создаем ПотокВПамяти.
  2. Создаем ЗаписьТекста, связанную с этим потоком.
  3. Записываем необходимые данные.
  4. Обязательно вызываем ЗаписьТекста.Закрыть(). Это «сбрасывает» буфер в поток и закрывает объект записи.
  5. Вызываем ПотокДанных.ЗакрытьИПолучитьДвоичныеДанные() для получения итогового результата.

Почему BOM может быть проблемой?

Выясним, зачем вообще нужно отключать BOM. В мире Windows маркер EF BB BF часто используется текстовыми редакторами (например, Блокнотом) для распознавания кодировки. Однако в веб-разработке и при передаче данных по протоколу HTTP наличие BOM в теле запроса (особенно в JSON или XML) часто считается ошибкой. Сервер может выдать ошибку «Unexpected character» (неожиданный символ), так как он ожидает увидеть в начале данных фигурную скобку { или тег <, а не служебные байты маркера кодировки.

Поэтому при формировании тела POST-запроса в 1С через потоки всегда проверяйте, требуется ли вашему контрагенту маркер BOM. В 90% случаев его следует отключать.

Сравнение методов: итоги

Подведем итог нашему анализу и сравним три способа получения двоичных данных из текста:

  1. Через временный файл: Самый медленный и «грязный» способ. Создает нагрузку на дисковую подсистему, требует прав на запись в папку временных файлов и всегда принудительно добавляет BOM.
  2. Через ПотокВПамяти: Гибкий метод, позволяет управлять BOM, подходит для сложных манипуляций (например, когда нужно собрать данные из нескольких источников в один поток).
  3. Через ПолучитьДвоичныеДанныеИзСтроки: Самый современный и производительный метод для простых случаев преобразования строки в байты.

Используя эти знания, мы можем эффективно управлять форматом данных и избегать трудноуловимых ошибок при интеграции 1С с внешними системами.

← На главную