Как записать данные в ZIP-архив через поток в памяти без использования временных файлов

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

При разработке интеграций, особенно при работе с HTTP-сервисами, часто возникает задача передать сжатые данные. Многие разработчики стремятся оптимизировать этот процесс, исключив запись промежуточных данных на диск, чтобы повысить производительность и избежать проблем с правами доступа к файловой системе. Однако при попытке реализовать это в среде 1С:Предприятие 8 можно столкнуться с неожиданными трудностями и путаницей в документации.

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

Различие между 1С:Предприятием и 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Файла в платформе 1С:Предприятие

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

Проанализируем метод Добавить() объекта ЗаписьZipФайла. Согласно документации и практике, этот метод в качестве первого параметра ожидает строку — полный путь к файлу на диске или маску. Он не умеет принимать объект Поток или ДвоичныеДанные напрямую. Если вы попытаетесь передать поток, система выдаст ошибку "Файл не обнаружен".

Таким образом, мы приходим к важному выводу: даже если сам архив формируется в памяти (через ПотокВПамяти), исходные данные для добавления в этот архив платформа требует "поднимать" с диска. Это делает невозможным создание полноценного ZIP-архива с файловой структурой абсолютно без использования файловой системы штатными средствами ЗаписьZipФайла.

Решение проблемы: Использование объекта СжатиеДанных

Если ваша задача заключается в сжатии данных для передачи через HTTP-сервис (например, для уменьшения объема трафика), и вам не принципиально наличие внутри архива конкретных имен файлов, мы рекомендуем использовать объект СжатиеДанных. Этот объект работает с форматами Gzip, Zlib или Deflate и полностью поддерживает работу с потоками в памяти.

Рассмотрим по шагам, как реализовать сжатие текста в ДвоичныеДанные без записи на диск:

  1. Создадим исходный поток данных в памяти.
  2. Запишем в него нужный текст или байты.
  3. Используем ЗаписьДанных совместно со СжатиеДанных для архивации "на лету".

Пример реализации на языке 1С:


// 1. Подготовим данные
ПотокИсходный = Новый ПотокВПамяти();
ЗаписьТекста = Новый ЗаписьДанных(ПотокИсходный);
ЗаписьТекста.ЗаписатьСтроку("Данные, которые нужно сжать для HTTP-запроса");
ЗаписьТекста.Закрыть();

// Получаем байты из исходного потока
ДвоичныеДанныеИсходные = ПотокИсходный.ЗакрытьИПолучитьДвоичныеДанные();

// 2. Сжимаем данные в новый поток
ПотокРезультат = Новый ПотокВПамяти();
// Используем формат Gzip, который понимает большинство веб-серверов
Сжатие = Новый СжатиеДанных(ПотокРезультат, ФорматСжатия.Gzip);

ЗаписьСжатыхДанных = Новый ЗаписьДанных(Сжатие);
ЗаписьСжатыхДанных.Записать(ДвоичныеДанныеИсходные);
ЗаписьСжатыхДанных.Закрыть();
Сжатие.Завершить();

// 3. Получаем итоговый сжатый пакет
ДвоичныеДанныеАрхива = ПотокРезультат.ЗакрытьИПолучитьДвоичныеДанные();

В данном примере мы полностью исключили обращение к жесткому диску. Объект ДвоичныеДанныеАрхива теперь можно передать в тело HTTP-запроса. Для отладки отправки таких запросов и проверки интеграции подойдёт обработка для тестирования REST API в среде 1С.

Альтернативные варианты

Если же спецификация вашего API жестко требует именно формат ZIP (с внутренней структурой папок и файлов) и при этом использование диска категорически запрещено, рассмотрим альтернативные пути:

Выясним причину, почему разработчики часто избегают временных файлов. Обычно это связано с боязнью "засорить" сервер. Чтобы этого не случилось, всегда используйте конструкцию Попытка...Исключение и удаляйте файл сразу после добавления в архив или отправки запроса:


ИмяФайла = ПолучитьИмяВременногоФайла("txt");
// Запись данных во временный файл...
// Сжатие...
Попытка
    УдалитьФайлы(ИмяФайла);
Исключение
    // Логируем ошибку, если файл занят
КонецПопытки;

Подводя итог, отметим: для эффективной работы в 1С важно четко разделять возможности встроенного языка платформы и сторонних инструментов вроде 1С:Исполнителя. Для задач "память-память" лучшим выбором остается СжатиеДанных в формате Gzip. Для решения смежных задач оптимизации объема передаваемой информации можно также изучить варианты сжатия строк средствами 1С.

← На главную