Архивация в ZIP средствами 1С:Предприятия: от одного файла до шифрованного архива

· 10 мин

Содержание

Сжать файл в ZIP в 1С можно без внешних программ: в платформе 8.3 для этого есть объект ЗаписьZipФайла. Три строки кода — создать объект с путём к архиву, вызвать Добавить() с путём к файлу и закончить вызовом Записать() — и архив готов.

Тот же объект умеет упаковывать целые каталоги с подпапками, менять уровень сжатия и ставить пароль с шифрованием AES. Внешние архиваторы вроде 7-Zip нужны только в особых случаях: многотомные архивы, формат 7z, жёсткие требования к степени сжатия.

Чем 1С сжимает файлы: объекты ЗаписьZipФайла и ЧтениеZipФайла

Для работы с архивами в платформе есть два объекта:

  • 📦 ЗаписьZipФайла — создаёт архив и добавляет в него файлы;
  • 📂 ЧтениеZipФайла — открывает готовый архив, показывает список элементов и распаковывает их.

Оба объекта работают с обычным форматом ZIP. Архив, созданный в 1С, открывается Проводником Windows, 7-Zip, WinRAR и любым архиватором в Linux. Обратное тоже верно.

Порядок работы с ЗаписьZipФайла всегда одинаковый:

  1. Создать объект конструктором Новый ЗаписьZipФайла(...) или методом Открыть(...).
  2. Добавить содержимое методом Добавить() — один или несколько раз.
  3. Вызвать Записать(). Только в этот момент архив физически формируется и закрывается.

Параметры конструктора идут в таком порядке:

№ПараметрЧто задаёт
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");

Что здесь происходит:

  1. Конструктор получает путь к будущему архиву. Если файл с таким именем есть, он будет перезаписан.
  2. Добавить() ставит файл в очередь на упаковку. Второй параметр НеСохранятьПути означает, что внутри архива окажется просто Остатки.xml, без цепочки D:\Обмен\.
  3. Записать() сжимает данные и закрывает архив.

Без вызова Записать() архив не будет создан или окажется пустым. Если между Добавить() и Записать() возникает исключение, оберните код в Попытка … Исключение и записывайте ошибку в журнал регистрации.

Режимы сохранения путей

Второй параметр Добавить() отвечает за то, как файл «ляжет» внутри архива:

Значение РежимСохраненияПутейZIPЧто внутри архиваКогда использовать
НеСохранятьПутиТолько имя файлаОдин файл или плоский набор
СохранятьОтносительныеПутиПодпапки относительно добавленного каталогаУпаковка папки со структурой
СохранятьПолныеПутиПолный путь с диском и всеми каталогамиПочти никогда: получатель видит вашу структуру дисков

Для отправки контрагенту или загрузки в сервис выбирайте первые два варианта.

Архивация каталога целиком и по маске

Чтобы сжать папку со всеми вложенными каталогами, передайте в Добавить() маску и включите рекурсивную обработку:

&НаСервереБезКонтекста
Процедура СжатьКаталог(Каталог, ПутьКАрхиву)

    Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
    Архив.Добавить(Каталог + "\*.*",
        РежимСохраненияПутейZIP.СохранятьОтносительныеПути,
        РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно);
    Архив.Записать();

КонецПроцедуры

Третий параметр — РежимОбработкиПодкаталоговZIP:

  • 🔁 ОбрабатыватьРекурсивно — берёт файлы из всех вложенных папок;
  • ⏹ НеОбрабатывать — только файлы верхнего уровня.

Маска работает и для выборочной упаковки. Например, Каталог + "\*.xml" соберёт только XML-файлы, а остальные останутся за бортом.

Сложный отбор: НайтиФайлы и цикл

Если правило отбора не описать маской (скажем, нужны файлы старше трёх дней или больше определённого размера), соберите список через НайтиФайлы() и добавляйте файлы по одному:

&НаСервереБезКонтекста
Процедура СжатьСтарыеЛоги(Каталог, ПутьКАрхиву)

    Граница = ТекущаяДатаСеанса() - 3 * 86400;
    Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
    ЕстьФайлы = Ложь;

    Для Каждого Файл Из НайтиФайлы(Каталог, "*.log", Ложь) Цикл
        Если Файл.ПолучитьВремяИзменения() < Граница Тогда
            Архив.Добавить(Файл.ПолноеИмя, РежимСохраненияПутейZIP.НеСохранятьПути);
            ЕстьФайлы = Истина;
        КонецЕсли;
    КонецЦикла;

    Если ЕстьФайлы Тогда
        Архив.Записать();
    КонецЕсли;

КонецПроцедуры

Флаг ЕстьФайлы нужен, чтобы не плодить пустые архивы, когда подходящих файлов нет. 3 * 86400 — три дня в секундах: к дате в 1С прибавляют и вычитают секунды.

Если в архив попадут два файла с одинаковым именем из разных папок, а пути не сохраняются, получатель увидит конфликт имён при распаковке. Для таких наборов используйте СохранятьОтносительныеПути и маску по каталогу.

Архив из двоичных данных: без файлов пользователя на диске

Частая задача: файл уже лежит в базе — в присоединённых файлах, во временном хранилище, в реквизите типа ХранилищеЗначения. Его нужно отдать пользователю или отправить по почте сразу в виде ZIP.

Метод Добавить() принимает путь к файлу, поэтому исходные данные один раз пишутся во временный каталог на сервере. Пользователь об этом не знает, а каталог удаляется сразу после упаковки:

&НаСервереБезКонтекста
Функция ЗаархивироватьДанные(ДвоичныеДанныеФайла, ИмяВнутриАрхива)

    ВременныйКаталог = ПолучитьИмяВременногоФайла();
    СоздатьКаталог(ВременныйКаталог);
    Разделитель = ПолучитьРазделительПути();

    ПутьКФайлу  = ВременныйКаталог + Разделитель + ИмяВнутриАрхива;
    ПутьКАрхиву = ВременныйКаталог + Разделитель + "archive.zip";

    ДвоичныеДанныеФайла.Записать(ПутьКФайлу);

    Архив = Новый ЗаписьZipФайла(ПутьКАрхиву);
    Архив.Добавить(ПутьКФайлу, РежимСохраненияПутейZIP.НеСохранятьПути);
    Архив.Записать();

    Результат = Новый ДвоичныеДанные(ПутьКАрхиву);
    УдалитьФайлы(ВременныйКаталог);

    Возврат Результат;

КонецФункции

Порядок важен: объект ДвоичныеДанные читает архив в память, и только потом каталог удаляется. ПолучитьРазделительПути() делает код рабочим и на Windows, и на Linux-сервере.

Как отдать архив пользователю

Дальше всё стандартно:

  1. На сервере поместите результат во временное хранилище: Адрес = ПоместитьВоВременноеХранилище(Результат, УникальныйИдентификатор);.
  2. На клиенте сохраните файл. В конфигурациях на БСП для этого есть ФайловаяСистемаКлиент.СохранитьФайл() — он сам покажет диалог и работает в веб-клиенте.
  3. Для почты передайте двоичные данные архива во вложение письма напрямую, без сохранения.

В новых релизах 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 чувствительны к регистру.