При выгрузке отчетов, пакетов первичных документов или наборов таблиц Excel часто возникает задача упаковать их в один общий ZIP-архив. Начинающие разработчики нередко сталкиваются с ситуацией, когда после завершения процедуры в архиве оказывается только один (последний) файл. Разберем причины такого поведения платформы 1С:Предприятие и рассмотрим правильные варианты решения этой задачи.
Проанализируем типовой фрагмент кода, приводящий к ошибке:
Для Каждого Файл Из МассивФайлов Цикл
ЗаписьZIP = Новый ЗаписьZipФайла(ИмяФайлаАрхива);
ЗаписьZIP.Добавить(Файл);
ЗаписьZIP.Записать();
КонецЦикла;
В приведенном коде допущены две критические ошибки логики работы с объектом ЗаписьZipФайла:
Новый ЗаписьZipФайла(...) по умолчанию инициализирует создание нового файла архива и затирает существующий файл на диске с таким же именем. В итоге при каждом шаге цикла архив перезаписывается заново.Записать() закрывает поток архива. После его вызова дальнейшая модификация данного объекта невозможна — для записи других файлов требуется либо открывать архив заново в специальном режиме, либо (что значительно проще и производительнее) добавлять все файлы до вызова Записать().Самый простой и прямолинейный способ упаковки нескольких файлов, разбросанных по разным путям или хранящихся в виде массива имен, — вынести создание и закрытие архива за пределы цикла добавления.
Посмотрим на пример правильного пошагового наполнения архива:
ИмяФайлаАрхива = "C:\Temp\ПакетДокументов.zip";
// Инициализируем архив один раз до начала цикла
ЗаписьZIP = Новый ЗаписьZipФайла(ИмяФайлаАрхива);
// Добавляем файлы по очереди
ЗаписьZIP.Добавить("C:\Temp\Накладная_1.xlsx");
ЗаписьZIP.Добавить("C:\Temp\Накладная_2.xlsx");
ЗаписьZIP.Добавить("C:\Temp\Счет_3.xlsx");
// Финализируем архив один раз после добавления всех файлов
ЗаписьZIP.Записать();
Если список файлов динамический, организуем аналогичную операцию в цикле:
ИмяФайлаАрхива = КаталогВременныхФайлов() + "Выгрузка.zip";
ЗаписьZIP = Новый ЗаписьZipФайла(ИмяФайлаАрхива);
Для Каждого ИмяФайла Из СписокПутейКФайлам Цикл
// Метод Добавить принимает путь к файлу и способ сохранения путей
ЗаписьZIP.Добавить(ИмяФайла, РежимСохраненияПутейZIP.НеСохранятьПути);
КонецЦикла;
// Закрываем и сохраняем архив на диске
ЗаписьZIP.Записать();
Обратите внимание на второй параметр метода Добавить(): перечисление РежимСохраненияПутейZIP.НеСохранятьПути гарантирует, что все файлы внутри архива попадут непосредственно в корень архива без воссоздания структуры папок вашего жесткого диска.
Если файлов много или они предварительно выгружаются обработкой во временную папку, удобнее упаковать каталог целиком либо использовать маску поиска (например, *.xlsx).
Разберем по шагам, как подготовить отдельную временную папку и упаковать её содержимое:
КаталогВременныхФайлов = КаталогВременныхФайлов();
КаталогДляФайлов = КаталогВременныхФайлов + "ЭкспортXLS\";
// 1. Проверяем существование каталога и создаем его при необходимости
КаталогНаДиске = Новый Файл(КаталогДляФайлов);
Если Не КаталогНаДиске.Существует() Тогда
СоздатьКаталог(КаталогДляФайлов);
КонецЕсли;
// 2. Здесь происходит формирование и сохранение файлов в КаталогДляФайлов...
// Например: ТабличныйДокумент.Записать(КаталогДляФайлов + "Отчет.xlsx", ТипФайлаТабличногоДокумента.XLSX);
// 3. Создаем ZIP-архив и упаковываем каталог
ПутьКАрхиву = КаталогВременныхФайлов + "ИтоговыйАрхив.zip";
Архиватор = Новый ЗаписьZipФайла(ПутьКАрхиву);
// Добавляем все файлы из папки с сохранением относительных путей или маской
Архиватор.Добавить(КаталогДляФайлов + "*.*", РежимСохраненияПутейZIP.НеСохранятьПути);
Архиватор.Записать();
// 4. Очищаем временную папку после упаковки при необходимости
УдалитьФайлы(КаталогДляФайлов);
При промышленной эксплуатации процедур архивации важно учитывать технические ограничения платформы 1С:
Попытка ... Исключение с выводом понятного сообщения пользователю.РежимСохраненияПутейZIP.НеСохранятьПути следите за тем, чтобы добавляемые файлы из разных каталогов не имели одинаковых имен, иначе более поздний файл перезапишет предыдущий внутри архива.ПотокВПамяти), передавая его первым параметром в конструктор ЗаписьZipФайла. Это исключает проблемы с правами на запись во временные каталоги файловой системы сервера.