При работе с внешними сервисами разработчики 1С часто сталкиваются с задачей передачи файлов через HTTP-запросы. Типичная проблема заключается в том, что при попытке прочитать файл (особенно бинарный, такой как PDF или картинку) стандартными текстовыми средствами, данные искажаются. В этой статье мы подробно разберем, почему привычное ЧтениеТекста не подходит для таких задач, и как реализовать корректную отправку данных, используя современные инструменты платформы 1С.
Рассмотрим причину, по которой автор темы не смог добиться соответствия данных с тем, что показывает Notepad++. Объект ЧтениеТекста предназначен исключительно для работы с текстовыми данными в определенных кодировках (UTF-8, Windows-1251 и др.).
Проанализируем ситуацию: файл PDF является бинарным. В нем содержатся байты, которые не имеют текстового представления в выбранной кодировке. Когда мы используем ЧтениеТекста:
ЗаписьТекста структура файла окончательно разрушается, и его размер меняется (как заметил автор в сообщении 14).Выясним причину использования Notepad++: этот редактор умеет отображать «сырые» байты в виде символов ASCII, даже если файл не является текстовым. Чтобы добиться такого же результата в 1С, нам нужно работать не с текстом, а с двоичными данными.
Если ваша задача — получить именно смысловое содержимое PDF (текст, который можно прочитать глазами), а не отправить сам файл, воспользуйтесь встроенным объектом ИзвлечениеТекста. Рассмотрим пример:
Попытка
Извлекатор = Новый ИзвлечениеТекста(ПутьКФайлу);
ТекстФайла = Извлекатор.ПолучитьТекст();
Сообщить(ТекстФайла);
Исключение
Сообщить("Не удалось извлечь текст: " + ОписаниеОшибки());
КонецПопытки;
Важный нюанс: этот метод работает на основе технологии Microsoft iFilter. Чтобы 1С «понимала» формат PDF, на сервере (или компьютере пользователя) должен быть установлен соответствующий фильтр (например, от Adobe или встроенный в Windows 10/11). Если фильтр не установлен, ИзвлечениеТекста вернет пустую строку или ошибку.
До появления развитых средств работы с потоками в 1С часто использовали COM-объект ADODB.Stream. Посмотрим на код, который приводил автор:
Файл = Новый COMОбъект("ADODB.Stream");
Файл.Type = 1; // adTypeBinary - работаем с байтами
Файл.Open();
Файл.LoadFromFile(ПутьКФайлу);
// Далее можно копировать в другой поток или сохранять
Хотя этот метод позволяет избежать искажения байтов, он крайне неудобен для формирования сложных HTTP-запросов и требует наличия установленных библиотек в системе, что затрудняет работу на Linux-серверах 1С.
Самый надежный и современный способ отправить файл через 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С следует придерживаться следующих правил:
ЧтениеТекста для бинарных файлов (PDF, XLS, PNG, EXE), если ваша цель — передать их содержимое без изменений.ДвоичныеДанные для получения содержимого файла «как есть».ИзвлечениеТекста (проверив наличие iFilter).ПотокВПамяти и ЗаписьДанных. Это гарантирует, что ни один байт не будет изменен из-за особенностей кодировок.multipart/form-data, Base64 обычно не нужен, данные передаются в «сыром» виде.Рассмотренный подход позволяет работать с файлами любого размера и формата, обеспечивая стопроцентную совместимость с веб-серверами, написанными на любых языках программирования.