Архивация в ZIP средствами 1С:Предприятия: от одного файла до шифрованного архива
Содержание
Сжать файл в ZIP в 1С можно без внешних программ: в платформе 8.3 для этого есть объект ЗаписьZipФайла. Три строки кода — создать объект с путём к архиву, вызвать Добавить() с путём к файлу и закончить вызовом Записать() — и архив готов.
Тот же объект умеет упаковывать целые каталоги с подпапками, менять уровень сжатия и ставить пароль с шифрованием AES. Внешние архиваторы вроде 7-Zip нужны только в особых случаях: многотомные архивы, формат 7z, жёсткие требования к степени сжатия.
Чем 1С сжимает файлы: объекты ЗаписьZipФайла и ЧтениеZipФайла
Для работы с архивами в платформе есть два объекта:
- 📦
ЗаписьZipФайла— создаёт архив и добавляет в него файлы; - 📂
ЧтениеZipФайла— открывает готовый архив, показывает список элементов и распаковывает их.
Оба объекта работают с обычным форматом ZIP. Архив, созданный в 1С, открывается Проводником Windows, 7-Zip, WinRAR и любым архиватором в Linux. Обратное тоже верно.
Порядок работы с ЗаписьZipФайла всегда одинаковый:
- Создать объект конструктором
Новый ЗаписьZipФайла(...)или методомОткрыть(...). - Добавить содержимое методом
Добавить()— один или несколько раз. - Вызвать
Записать(). Только в этот момент архив физически формируется и закрывается.
Параметры конструктора идут в таком порядке:
| № | Параметр | Что задаёт |
|---|---|---|
| 1 | ИмяФайла | Полный путь к создаваемому архиву |
| 2 | Пароль | Строка пароля; пусто — без пароля |
| 3 | Комментарий | Текстовый комментарий архива |
| 4 | МетодСжатия | МетодСжатияZIP.Сжатие или МетодСжатияZIP.Копирование |
| 5 | УровеньСжатия | УровеньСжатияZIP.Минимальный, Оптимальный, Максимальный |
| 6 | МетодШифрования | МетодШифрованияZIP.Zip20, AES128, AES192, AES256 |
| 7 | КодировкаИменФайлов | Кодировка имён внутри архива, например UTF8 |
Все параметры, кроме первого, необязательны. Пропущенные заменяйте запятыми.
Точный список параметров для вашего релиза платформы смотрите в синтакс-помощнике Конфигуратора: откройте Справка → Синтакс-помощник и введите в поиск «ЗаписьZipФайла».
Где выполнять код
Объект работает на сервере, в тонком и толстом клиенте. В веб-клиенте его нет, поэтому универсальный вариант — архивировать на сервере, а результат передавать клиенту через временное хранилище.
При этом пути считаются от того компьютера, где выполняется код. Процедура с директивой &НаСервере ищет C:\Обмен\отчет.xlsx на диске сервера 1С, а не на ПК пользователя. Это главная ловушка, о ней ниже в разделе ошибок.
Сжимаем один файл в ZIP: пошагово
Минимальный рабочий пример. Файл кладётся в корень архива, без папок:
&НаСервереБезКонтекста
Процедура СжатьФайлВZip(ПутьКФайлу, ПутьКАрхиву)
Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
Архив.Добавить(ПутьКФайлу, РежимСохраненияПутейZIP.НеСохранятьПути);
Архив.Записать();
КонецПроцедуры
Вызов:
СжатьФайлВZip("D:\Обмен\Остатки.xml", "D:\Обмен\Остатки.zip");
Что здесь происходит:
- Конструктор получает путь к будущему архиву. Если файл с таким именем есть, он будет перезаписан.
Добавить()ставит файл в очередь на упаковку. Второй параметрНеСохранятьПутиозначает, что внутри архива окажется простоОстатки.xml, без цепочкиD:\Обмен\.Записать()сжимает данные и закрывает архив.
Без вызова Записать() архив не будет создан или окажется пустым. Если между Добавить() и Записать() возникает исключение, оберните код в Попытка … Исключение и записывайте ошибку в журнал регистрации.
Режимы сохранения путей
Второй параметр Добавить() отвечает за то, как файл «ляжет» внутри архива:
Значение РежимСохраненияПутейZIP | Что внутри архива | Когда использовать |
|---|---|---|
НеСохранятьПути | Только имя файла | Один файл или плоский набор |
СохранятьОтносительныеПути | Подпапки относительно добавленного каталога | Упаковка папки со структурой |
СохранятьПолныеПути | Полный путь с диском и всеми каталогами | Почти никогда: получатель видит вашу структуру дисков |
Для отправки контрагенту или загрузки в сервис выбирайте первые два варианта.
Архивация каталога целиком и по маске
Чтобы сжать папку со всеми вложенными каталогами, передайте в Добавить() маску и включите рекурсивную обработку:
&НаСервереБезКонтекста
Процедура СжатьКаталог(Каталог, ПутьКАрхиву)
Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
Архив.Добавить(Каталог + "\*.*",
РежимСохраненияПутейZIP.СохранятьОтносительныеПути,
РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно);
Архив.Записать();
КонецПроцедуры
Третий параметр — РежимОбработкиПодкаталоговZIP:
- 🔁
ОбрабатыватьРекурсивно— берёт файлы из всех вложенных папок; - ⏹
НеОбрабатывать— только файлы верхнего уровня.
Маска работает и для выборочной упаковки. Например, Каталог + "\*.xml" соберёт только XML-файлы, а остальные останутся за бортом.
Сложный отбор: НайтиФайлы и цикл
Если правило отбора не описать маской (скажем, нужны файлы старше трёх дней или больше определённого размера), соберите список через НайтиФайлы() и добавляйте файлы по одному:
&НаСервереБезКонтекста
Процедура СжатьСтарыеЛоги(Каталог, ПутьКАрхиву)
Граница = ТекущаяДатаСеанса() - 3 * 86400;
Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
ЕстьФайлы = Ложь;
Для Каждого Файл Из НайтиФайлы(Каталог, "*.log", Ложь) Цикл
Если Файл.ПолучитьВремяИзменения() < Граница Тогда
Архив.Добавить(Файл.ПолноеИмя, РежимСохраненияПутейZIP.НеСохранятьПути);
ЕстьФайлы = Истина;
КонецЕсли;
КонецЦикла;
Если ЕстьФайлы Тогда
Архив.Записать();
КонецЕсли;
КонецПроцедуры
Флаг ЕстьФайлы нужен, чтобы не плодить пустые архивы, когда подходящих файлов нет. 3 * 86400 — три дня в секундах: к дате в 1С прибавляют и вычитают секунды.
Если в архив попадут два файла с одинаковым именем из разных папок, а пути не сохраняются, получатель увидит конфликт имён при распаковке. Для таких наборов используйте СохранятьОтносительныеПути и маску по каталогу.
Архив из двоичных данных: без файлов пользователя на диске
Частая задача: файл уже лежит в базе — в присоединённых файлах, во временном хранилище, в реквизите типа ХранилищеЗначения. Его нужно отдать пользователю или отправить по почте сразу в виде ZIP.
Метод Добавить() принимает путь к файлу, поэтому исходные данные один раз пишутся во временный каталог на сервере. Пользователь об этом не знает, а каталог удаляется сразу после упаковки:
&НаСервереБезКонтекста
Функция ЗаархивироватьДанные(ДвоичныеДанныеФайла, ИмяВнутриАрхива)
ВременныйКаталог = ПолучитьИмяВременногоФайла();
СоздатьКаталог(ВременныйКаталог);
Разделитель = ПолучитьРазделительПути();
ПутьКФайлу = ВременныйКаталог + Разделитель + ИмяВнутриАрхива;
ПутьКАрхиву = ВременныйКаталог + Разделитель + "archive.zip";
ДвоичныеДанныеФайла.Записать(ПутьКФайлу);
Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
Архив.Добавить(ПутьКФайлу, РежимСохраненияПутейZIP.НеСохранятьПути);
Архив.Записать();
Результат = Новый ДвоичныеДанные(ПутьКАрхиву);
УдалитьФайлы(ВременныйКаталог);
Возврат Результат;
КонецФункции
Порядок важен: объект ДвоичныеДанные читает архив в память, и только потом каталог удаляется. ПолучитьРазделительПути() делает код рабочим и на Windows, и на Linux-сервере.
Как отдать архив пользователю
Дальше всё стандартно:
- На сервере поместите результат во временное хранилище:
Адрес = ПоместитьВоВременноеХранилище(Результат, УникальныйИдентификатор);. - На клиенте сохраните файл. В конфигурациях на БСП для этого есть
ФайловаяСистемаКлиент.СохранитьФайл()— он сам покажет диалог и работает в веб-клиенте. - Для почты передайте двоичные данные архива во вложение письма напрямую, без сохранения.
В новых релизах 8.3 конструктор ЗаписьZipФайла принимает вместо имени файла поток, например ПотокВПамяти. Тогда сам архив собирается в оперативной памяти. Доступен ли этот вариант в вашей версии, проверьте в синтакс-помощнике по списку вариантов конструктора.
Уровень сжатия, пароль и шифрование AES
Насколько сильно сжимать
УровеньСжатияZIP меняет баланс между размером и временем:
| Уровень | Скорость | Размер архива | Где уместен |
|---|---|---|---|
Минимальный | Самая высокая | Больше остальных | Регулярные выгрузки по расписанию, большие объёмы |
Оптимальный | Средняя | Средний | Вариант по умолчанию для большинства задач |
Максимальный | Самая низкая | Минимальный | Отправка по почте с лимитом на вложение |
Текстовые форматы — XML, JSON, CSV, выгрузки обмена — ужимаются в разы. А вот PDF, JPEG, DOCX и XLSX уже сжаты внутри, и выигрыш от архивации у них небольшой. Для них разумно взять МетодСжатияZIP.Копирование: файлы просто складываются в архив без пересжатия, это быстро и почти не грузит процессор сервера.
Архив с паролем
Пароль — второй параметр, метод шифрования — шестой:
Архив = Новый ЗаписьZipФайла(ПутьКАрхиву,
"Kx7#pL2q", // пароль
"Реестр за сентябрь", // комментарий
МетодСжатияZIP.Сжатие,
УровеньСжатияZIP.Оптимальный,
МетодШифрованияZIP.AES256);
Чем отличаются методы шифрования:
- 🔓
Zip20— классическое шифрование ZIP. Открывается практически везде, но стойкость низкая: подходит разве что против случайного просмотра. - 🔐
AES128,AES192,AES256— стойкое шифрование. Для персональных данных и зарплатных реестров беритеAES256.
Встроенный архиватор Проводника Windows исторически поддерживает только классическое шифрование ZIP. Архив с AES получатель может не открыть стандартными средствами — предупредите его заранее, что нужен 7-Zip или аналог.
Не храните пароль строкой в модуле. Его увидит любой, у кого есть доступ к Конфигуратору или выгрузке конфигурации. Держите пароль в константе или регистре сведений с ограниченными правами и передавайте получателю отдельным каналом, не в том же письме.
Кириллица в именах файлов
Если получатель видит вместо Остатки.xml набор символов вроде ЋбІ ⇄Ё.xml, укажите седьмой параметр — кодировку имён UTF8. Современные архиваторы корректно читают такие имена. Если файл уходит в старую учётную систему, проще сразу давать вложенным файлам латинские имена.
Внешние архиваторы: 7-Zip и COM-объект Windows
Встроенного объекта хватает почти всегда. Внешний инструмент оправдан, когда нужно:
- 🧩 разбить архив на тома фиксированного размера;
- 🗜 получить формат 7z или максимальное сжатие больших баз выгрузки;
- 🖥 повторить настройки, принятые в компании для всех архивов.
Вызов 7-Zip из кода
7-Zip запускается через командную строку методом ЗапуститьПриложение(). Третий параметр Истина заставляет 1С дождаться окончания упаковки, а в четвёртый возвращается код завершения:
Команда = """C:\Program Files\7-Zip\7z.exe"" a -tzip -mx=9 "
+ """" + ПутьКАрхиву + """ """ + Каталог + "\*""";
КодВозврата = 0;
ЗапуститьПриложение(Команда, , Истина, КодВозврата);
Если КодВозврата <> 0 Тогда
ВызватьИсключение "7-Zip завершился с кодом " + Формат(КодВозврата, "ЧГ=0");
КонецЕсли;
Ключи командной строки:
| Ключ | Назначение |
|---|---|
a | Добавить файлы в архив |
-tzip | Формат ZIP (без ключа будет 7z) |
-mx=9 | Максимальная степень сжатия, -mx=1 — самая быстрая |
-pПароль | Пароль на архив |
-mem=AES256 | Шифрование AES-256 для формата ZIP |
-v100m | Разбить на тома по 100 МБ |
Код возврата 0 означает успех. Ненулевое значение — повод записать ошибку в журнал и не отправлять получателю битый архив.
Если код выполняется на сервере 1С, 7-Zip должен быть установлен именно на сервере, а пути к файлам — доступны пользователю, от имени которого работает служба сервера.
COM-объект Shell.Application
Второй внешний способ — объект Windows Shell.Application, который использует встроенный архиватор Проводника. Работает он только на Windows, копирует файлы асинхронно и не сообщает, когда закончил. Приходится ждать в цикле и сверять число элементов в архиве. Для новых разработок этот путь не стоит выбирать: ЗаписьZipФайла делает то же самое надёжнее и без зависимости от ОС.
Сравнение способов
| Способ | Когда выбирать | Риски |
|---|---|---|
ЗаписьZipФайла | Почти всегда: файлы, каталоги, пароль, AES | Нет многотомных архивов и формата 7z |
7-Zip через ЗапуститьПриложение() | Тома, 7z, корпоративные требования | Нужно ставить программу на каждый сервер |
Shell.Application | Только поддержка старого кода | Асинхронность, только Windows, нет пароля |
Проверка результата и распаковка через ЧтениеZipФайла
Перед отправкой архива полезно убедиться, что внутри то, что нужно. ЧтениеZipФайла открывает архив и даёт коллекцию Элементы:
Чтение = Новый ЧтениеZipФайла(ПутьКАрхиву);
Для Каждого Элемент Из Чтение.Элементы Цикл
Сообщить(Элемент.ПолноеИмя + " — " + Формат(Элемент.РазмерНесжатого, "ЧГ=0") + " байт");
КонецЦикла;
Чтение.Закрыть();
Если коллекция пуста, архив собран с ошибкой — отправлять его нельзя. Для распаковки всего содержимого используйте Чтение.ИзвлечьВсе(Каталог), для архива с паролем передайте пароль вторым параметром конструктора.
Ошибки при архивации и как их устранить
Ещё одна неочевидная ситуация — объект ЗаписьZipФайла недоступен в модуле формы. Обычно это значит, что код помечен директивой &НаКлиенте и запускается в веб-клиенте. Перенесите архивацию в серверную процедуру.
Частые вопросы
Можно ли добавить файлы в уже существующий ZIP-архив средствами 1С?
ЗаписьZipФайла не умеет: при записи файл создаётся заново. Распакуйте старый архив через ЧтениеZipФайла во временный каталог, добавьте новые файлы и соберите архив повторно.Сожмёт ли ZIP выгрузку базы в формате .dt?
Как архивировать файлы по расписанию?
Работает ли ЗаписьZipФайла на Linux-сервере 1С?
ПолучитьРазделительПути() вместо жёсткого обратного слеша и помните, что имена файлов в Linux чувствительны к регистру.