При разработке интеграций, особенно при работе с HTTP-сервисами, часто возникает задача передать сжатые данные. Многие разработчики стремятся оптимизировать этот процесс, исключив запись промежуточных данных на диск, чтобы повысить производительность и избежать проблем с правами доступа к файловой системе. Однако при попытке реализовать это в среде 1С:Предприятие 8 можно столкнуться с неожиданными трудностями и путаницей в документации.
В рамках данной статьи мы разберем, почему стандартные примеры с сайта ИТС могут не работать в конфигураторе, выясним разницу между различными инструментами 1С и найдем эффективные способы сжатия данных в оперативной памяти.
Первым делом проанализируем ситуацию, когда разработчик находит описание объекта ЗаписьZip (ZipWriter) и пытается применить его в обычном коде 1С. Важно понимать, что компания "1С" развивает несколько технологических направлений. Объект ЗаписьZip, поддерживающий метод Добавить() с передачей потока, относится к 1С:Исполнителю (1C:Executor).
1С:Исполнитель — это отдельная среда выполнения скриптов, которая имеет свой собственный синтаксис и объектную модель, отличную от привычной платформы "1С:Предприятие 8". В стандартном конфигураторе (даже в самых свежих версиях 8.3) объект ЗаписьZip отсутствует, а вместо него используется ЗаписьZipФайла.
Рассмотрим пример кода, который часто вводит в заблуждение, так как он предназначен для 1С:Исполнителя:
// Этот код НЕ будет работать в обычном конфигураторе 1С
метод СформироватьАрхив(Каталог: Файл, ВыходнойАрхив: Файл)
исп ПотокЗаписи = ВыходнойАрхив.ОткрытьПотокЗаписи()
пер ЗаписьZip = новый ЗаписьZip(ПотокЗаписи, "password", УровеньСжатияZip.Нормальный, МетодШифрованияZip.Aes256)
// ...
ЗаписьZip.Добавить(Файл.ОткрытьПотокЧтения(), Файл.Имя)
ЗаписьZip.Записать()
;
Теперь перейдем к привычной нам платформе. Здесь существует объект ЗаписьZipФайла. Начиная с определенных версий платформы, его конструктор действительно позволяет инициализировать архив на базе потока (например, ПотокВПамяти), что позволяет записать результат архивации сразу в память. Однако здесь кроется главная проблема.
Проанализируем метод Добавить() объекта ЗаписьZipФайла. Согласно документации и практике, этот метод в качестве первого параметра ожидает строку — полный путь к файлу на диске или маску. Он не умеет принимать объект Поток или ДвоичныеДанные напрямую. Если вы попытаетесь передать поток, система выдаст ошибку "Файл не обнаружен".
Таким образом, мы приходим к важному выводу: даже если сам архив формируется в памяти (через ПотокВПамяти), исходные данные для добавления в этот архив платформа требует "поднимать" с диска. Это делает невозможным создание полноценного ZIP-архива с файловой структурой абсолютно без использования файловой системы штатными средствами ЗаписьZipФайла.
Если ваша задача заключается в сжатии данных для передачи через HTTP-сервис (например, для уменьшения объема трафика), и вам не принципиально наличие внутри архива конкретных имен файлов, мы рекомендуем использовать объект СжатиеДанных. Этот объект работает с форматами Gzip, Zlib или Deflate и полностью поддерживает работу с потоками в памяти.
Рассмотрим по шагам, как реализовать сжатие текста в ДвоичныеДанные без записи на диск:
ЗаписьДанных совместно со СжатиеДанных для архивации "на лету".Пример реализации на языке 1С:
// 1. Подготовим данные
ПотокИсходный = Новый ПотокВПамяти();
ЗаписьТекста = Новый ЗаписьДанных(ПотокИсходный);
ЗаписьТекста.ЗаписатьСтроку("Данные, которые нужно сжать для HTTP-запроса");
ЗаписьТекста.Закрыть();
// Получаем байты из исходного потока
ДвоичныеДанныеИсходные = ПотокИсходный.ЗакрытьИПолучитьДвоичныеДанные();
// 2. Сжимаем данные в новый поток
ПотокРезультат = Новый ПотокВПамяти();
// Используем формат Gzip, который понимает большинство веб-серверов
Сжатие = Новый СжатиеДанных(ПотокРезультат, ФорматСжатия.Gzip);
ЗаписьСжатыхДанных = Новый ЗаписьДанных(Сжатие);
ЗаписьСжатыхДанных.Записать(ДвоичныеДанныеИсходные);
ЗаписьСжатыхДанных.Закрыть();
Сжатие.Завершить();
// 3. Получаем итоговый сжатый пакет
ДвоичныеДанныеАрхива = ПотокРезультат.ЗакрытьИПолучитьДвоичныеДанные();
В данном примере мы полностью исключили обращение к жесткому диску. Объект ДвоичныеДанныеАрхива теперь можно передать в тело HTTP-запроса. Для отладки отправки таких запросов и проверки интеграции подойдёт обработка для тестирования REST API в среде 1С.
Если же спецификация вашего API жестко требует именно формат ZIP (с внутренней структурой папок и файлов) и при этом использование диска категорически запрещено, рассмотрим альтернативные пути:
System.IO.Compression, где классы ZipArchive позволяют добавлять элементы из потоков.ПолучитьИмяВременногоФайла(). Это стандартный и самый надежный способ для 1С. Современные системы часто кэшируют операции с временными файлами в оперативной памяти (на уровне ОС), поэтому реального обращения к физическому диску может и не произойти.Выясним причину, почему разработчики часто избегают временных файлов. Обычно это связано с боязнью "засорить" сервер. Чтобы этого не случилось, всегда используйте конструкцию Попытка...Исключение и удаляйте файл сразу после добавления в архив или отправки запроса:
ИмяФайла = ПолучитьИмяВременногоФайла("txt");
// Запись данных во временный файл...
// Сжатие...
Попытка
УдалитьФайлы(ИмяФайла);
Исключение
// Логируем ошибку, если файл занят
КонецПопытки;
Подводя итог, отметим: для эффективной работы в 1С важно четко разделять возможности встроенного языка платформы и сторонних инструментов вроде 1С:Исполнителя. Для задач "память-память" лучшим выбором остается СжатиеДанных в формате Gzip. Для решения смежных задач оптимизации объема передаваемой информации можно также изучить варианты сжатия строк средствами 1С.