Как правильно извлечь данные из файла и отправить их через HTTP POST в 1С?

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

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

Почему стандартное чтение текста «коверкает» файлы?

Рассмотрим причину, по которой автор темы не смог добиться соответствия данных с тем, что показывает Notepad++. Объект ЧтениеТекста предназначен исключительно для работы с текстовыми данными в определенных кодировках (UTF-8, Windows-1251 и др.).

Проанализируем ситуацию: файл PDF является бинарным. В нем содержатся байты, которые не имеют текстового представления в выбранной кодировке. Когда мы используем ЧтениеТекста:

  1. Платформа пытается интерпретировать каждый байт или последовательность байтов как символ.
  2. Если встречается байт, не входящий в кодировку (например, в UTF-8), он заменяется на спецсимвол или просто теряется.
  3. Символы с нулевым кодом (Null-bytes) могут обрывать чтение строки.
  4. При обратной записи через ЗаписьТекста структура файла окончательно разрушается, и его размер меняется (как заметил автор в сообщении 14).

Выясним причину использования Notepad++: этот редактор умеет отображать «сырые» байты в виде символов ASCII, даже если файл не является текстовым. Чтобы добиться такого же результата в 1С, нам нужно работать не с текстом, а с двоичными данными.

Способ 1: Использование объекта ИзвлечениеТекста

Если ваша задача — получить именно смысловое содержимое PDF (текст, который можно прочитать глазами), а не отправить сам файл, воспользуйтесь встроенным объектом ИзвлечениеТекста. Рассмотрим пример:


Попытка
    Извлекатор = Новый ИзвлечениеТекста(ПутьКФайлу);
    ТекстФайла = Извлекатор.ПолучитьТекст();
    Сообщить(ТекстФайла);
Исключение
    Сообщить("Не удалось извлечь текст: " + ОписаниеОшибки());
КонецПопытки;

Важный нюанс: этот метод работает на основе технологии Microsoft iFilter. Чтобы 1С «понимала» формат PDF, на сервере (или компьютере пользователя) должен быть установлен соответствующий фильтр (например, от Adobe или встроенный в Windows 10/11). Если фильтр не установлен, ИзвлечениеТекста вернет пустую строку или ошибку.

Способ 2: Работа через ADODB.Stream (устаревший вариант)

До появления развитых средств работы с потоками в 1С часто использовали COM-объект ADODB.Stream. Посмотрим на код, который приводил автор:


Файл = Новый COMОбъект("ADODB.Stream");
Файл.Type = 1; // adTypeBinary - работаем с байтами
Файл.Open();
Файл.LoadFromFile(ПутьКФайлу);
// Далее можно копировать в другой поток или сохранять

Хотя этот метод позволяет избежать искажения байтов, он крайне неудобен для формирования сложных HTTP-запросов и требует наличия установленных библиотек в системе, что затрудняет работу на Linux-серверах 1С.

Способ 3: Правильное решение — ПотокВПамяти и ЗаписьДанных

Самый надежный и современный способ отправить файл через HTTP POST (особенно если требуется формат multipart/form-data) — это использование потоков. Разберем по шагам итоговое решение, к которому пришел автор обсуждения.

Суть метода заключается в том, что мы не переводим файл в строку. Мы формируем тело запроса как единую последовательность байтов, в которую «вклеиваем» содержимое файла в его первозданном виде.

Реализация функции формирования тела запроса

Проанализируем программный код функции, которая подготавливает данные для отправки:


Функция СоздатьСообщениеСДанными(ИмяФайлаЗагрузки, ПутьКФайлу, Boundary)
    Поток = Новый ПотокВПамяти();
    ЗаписьДанных = Новый ЗаписьДанных(Поток);
    
    // 1. Записываем заголовок части multipart
    ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""file""; filename=""" + ИмяФайлаЗагрузки + """");
    ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/pdf");
    
    // 2. Пустая строка отделяет заголовки от тела данных
    ЗаписьДанных.ЗаписатьСтроку("");
    
    // 3. Читаем файл как бинарные данные и записываем напрямую в поток
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
    ЗаписьДанных.Записать(ДвоичныеДанныеФайла);
    
    // Завершаем запись
    ЗаписьДанных.Закрыть();
    
    // Возвращаем результат как ДвоичныеДанные
    Возврат Поток.ЗакрытьИПолучитьДвоичныеДанные();
КонецФункции

В этом коде критически важен объект ЗаписьДанных. Он позволяет комбинировать текстовые строки (заголовки) и сырые байты (содержимое PDF), не пытаясь конвертировать последние.

Отправка сформированного запроса

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


Boundary = СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "");
Ресурс = "/api/upload";
Соединение = Новый HTTPСоединение("server-address.com");

ПотокоТело = Новый ПотокВПамяти();
ЗаписьТекста = Новый ЗаписьДанных(ПотокоТело); 

// Формируем структуру multipart
ЗаписьТекста.ЗаписатьСтроку("--" + Boundary);
ДанныеФайла = СоздатьСообщениеСДанными("document.pdf", "C:\files\doc.pdf", Boundary);
ЗаписьТекста.Записать(ДанныеФайла);
ЗаписьТекста.ЗаписатьСтроку("");
ЗаписьТекста.ЗаписатьСтроку("--" + Boundary + "--");

ДвоичныеДанныеТело = ПотокоТело.ЗакрытьИПолучитьДвоичныеДанные();

ЗаголовокHTTP = Новый Соответствие();
ЗаголовокHTTP.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);

Запрос = Новый HTTPЗапрос(Ресурс, ЗаголовокHTTP);
Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанныеТело);

Ответ = Соединение.ОтправитьДляОбработки(Запрос);

Подведем итоги

Для успешного извлечения и передачи данных из файлов в 1С следует придерживаться следующих правил:

  1. Никогда не используйте ЧтениеТекста для бинарных файлов (PDF, XLS, PNG, EXE), если ваша цель — передать их содержимое без изменений.
  2. Используйте ДвоичныеДанные для получения содержимого файла «как есть».
  3. Если нужно извлечь только читаемый текст из PDF, используйте объект ИзвлечениеТекста (проверив наличие iFilter).
  4. Для формирования HTTP-запросов применяйте связку ПотокВПамяти и ЗаписьДанных. Это гарантирует, что ни один байт не будет изменен из-за особенностей кодировок.
  5. Помните, что Base64 — это способ передачи бинарных данных внутри текстовых протоколов (JSON, XML). Если API требует multipart/form-data, Base64 обычно не нужен, данные передаются в «сыром» виде.

Рассмотренный подход позволяет работать с файлами любого размера и формата, обеспечивая стопроцентную совместимость с веб-серверами, написанными на любых языках программирования.

← На главную