Сжатие и распаковка ZIP средствами встроенного языка 1С:Предприятия 8.3

· 9 мин

Содержание

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

Всё остальное — детали, на которых обычно и спотыкаются: где выполняется код (клиент или сервер), как собрать пути, что делать с кириллицей в именах, как отдать архив пользователю и не оставить мусор во временном каталоге. Ниже код для управляемых форм и платформы 8.3.2x, тема общая для всех конфигураций.

Какие объекты платформы работают с ZIP-архивами

Платформа поддерживает только формат ZIP. Форматы RAR и 7z встроенными средствами не создаются и не читаются.

ОбъектДля чего нужен
ЗаписьZipФайлаСоздать архив, добавить файлы и каталоги, задать пароль и степень сжатия
ЧтениеZipФайлаОткрыть архив, получить список элементов, извлечь всё или выборочно
ЭлементZipФайлаОдин файл внутри архива: имя, полное имя с путём, признак шифрования

Параметры архива задаются системными перечислениями:

  • 📦 МетодСжатияZIP — Сжатие или Копирование (файлы складываются без сжатия, быстро);
  • 🎚️ УровеньСжатияZIP — Минимальный, Оптимальный, Максимальный;
  • 🔐 МетодШифрованияZIP — Zip20, AES128, AES192, AES256;
  • 🔤 КодировкаИменФайловВZIPФайле — Авто, UTF8, КодировкаОСДополнительноUTF8;
  • 📁 РежимСохраненияПутейZIP — НеСохранятьПути, СохранятьОтносительныеПути, СохранятьПолныеПути;
  • 🔁 РежимОбработкиПодкаталоговZIP — НеОбрабатывать или ОбрабатыватьРекурсивно;
  • 📤 РежимВосстановленияПутейФайловZIP — Восстанавливать или НеВосстанавливать при распаковке.

Точный состав параметров конструктора и методов для своей версии платформы проверяйте в синтакс-помощнике: открывается по Shift+F1 в конфигураторе, поиск по слову «Zip».

Если нужен формат, отличный от ZIP, остаётся только запуск внешнего архиватора через ЗапуститьПриложение() или КомандаСистемы(). Это работает, пока архиватор установлен на той машине, где выполняется код, и пока у пользователя есть права на запуск.

Подготовка: где выполняется код, пути и временные файлы

Прежде чем писать архивацию, решите, на какой стороне она пойдёт.

Клиент или сервер

В клиент-серверной базе сервер 1С видит свою файловую систему, а не диск пользователя. Путь C:\Users\Иванов\Desktop\Акты в серверной процедуре окажется пустым или вовсе не найдётся.

Рабочая схема для управляемой формы:

  1. Файлы, которые лежат у пользователя, передайте на сервер через временное хранилище (метод помещения файлов на клиенте, в типовых на БСП — ФайловаяСистемаКлиент).
  2. Архив собирайте в процедуре &НаСервере во временном каталоге сервера.
  3. Готовый архив прочитайте в ДвоичныеДанные, положите во временное хранилище и отдайте клиенту адрес.
  4. Временный файл архива сразу удалите.

Служба сервера 1С работает под своей учётной записью, обычно USR1CV8. Если архив пишется в сетевую папку или на другой диск сервера, права на запись нужны именно этой учётной записи, а не пользователю 1С.

Сборка путей

Чтобы код работал и на Windows, и на Linux-сервере, не вписывайте обратный слеш руками:

  • ПолучитьРазделительПути() вернёт \ или / в зависимости от ОС;
  • КаталогВременныхФайлов() — временный каталог текущего сеанса;
  • ПолучитьИмяВременногоФайла("zip") — уникальное имя файла с нужным расширением;
  • Новый Файл(Путь) с методами Существует() и ЭтоКаталог() — проверка до начала работы;
  • НайтиФайлы(Каталог, "*.pdf", Истина) — отбор файлов по маске, третий параметр включает поиск в подкаталогах.
&НаСервереБезКонтекста
Функция ДобавитьРазделитель(Каталог)
	Разделитель = ПолучитьРазделительПути();
	Если СтрЗаканчиваетсяНа(Каталог, Разделитель) Тогда
		Возврат Каталог;
	КонецЕсли;
	Возврат Каталог + Разделитель;
КонецФункции

Маска *.* в Linux не находит файлы без расширения. Если на сервере под Linux встречаются такие файлы, используйте маску *.

Как создать ZIP-архив в 1С: пошаговый пример

Задача: упаковать каталог со всеми подкаталогами, сохранить структуру папок и отдать архив пользователю.

Шаг 1. Создаём объект записи

Конструктор принимает имя архива, пароль, комментарий, метод и уровень сжатия, метод шифрования и кодировку имён. Ненужные параметры пропускаются запятыми.

Шаг 2. Добавляем файлы

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

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

Шаг 3. Записываем и забираем результат

Пока не вызван Записать(), архива на диске нет. После записи файл можно читать.

&НаСервере
Функция СоздатьАрхивКаталогаНаСервере(КаталогИсточник)

	ИмяАрхива = ПолучитьИмяВременногоФайла("zip");

	Архив = Новый ЗаписьZipФайла(ИмяАрхива, , "Выгрузка документов",
		МетодСжатияZIP.Сжатие,
		УровеньСжатияZIP.Оптимальный, ,
		КодировкаИменФайловВZIPФайле.UTF8);

	Архив.Добавить(ДобавитьРазделитель(КаталогИсточник) + "*",
		РежимСохраненияПутейZIP.СохранятьОтносительныеПути,
		РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно);

	Архив.Записать();

	Данные = Новый ДвоичныеДанные(ИмяАрхива);
	УдалитьФайлы(ИмяАрхива);

	Возврат ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);

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

На клиенте полученный адрес передают в метод сохранения файла. В конфигурациях на БСП это ФайловаяСистемаКлиент.СохранитьФайл, он сам откроет диалог выбора места.

Выборочная упаковка

Если в архив нужны не все файлы, а, например, только PDF больше нуля байт, отберите их сами и добавляйте по одному:

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

При НеСохранятьПути два файла акт.pdf из разных папок столкнутся по имени. Если такое возможно, сначала скопируйте файлы во временный каталог под уникальными именами и упакуйте его.

Пароль и шифрование

Пароль задаётся вторым параметром конструктора, метод шифрования — шестым.

  • 🔓 Zip20 откроет любой архиватор, включая проводник Windows, но защита слабая.
  • 🔒 AES256 надёжнее, однако встроенный в Windows распаковщик такие архивы не открывает. Получателю понадобится 7-Zip или аналог.

Не храните пароль в тексте модуля. Берите его из константы с ограниченными правами или передавайте параметром.

Кириллица в именах файлов

Если получатель видит в архиве нечитаемые имена, дело в кодировке. UTF8 правильно читают современные архиваторы. Для старых программ и для пользователей, которые открывают ZIP проводником, попробуйте КодировкаОСДополнительноUTF8: имя пишется в кодировке ОС и дополнительно в UTF-8.

Распаковка и чтение содержимого ZIP

ЧтениеZipФайла открывает архив и даёт коллекцию Элементы. Перебором можно посмотреть состав, не распаковывая ничего на диск.

&НаСервереБезКонтекста
Функция РаспаковатьXMLИзАрхива(ДанныеАрхива, Пароль = "")

	ИмяАрхива = ПолучитьИмяВременногоФайла("zip");
	ДанныеАрхива.Записать(ИмяАрхива);

	КаталогРаспаковки = ДобавитьРазделитель(ПолучитьИмяВременногоФайла(""));
	СоздатьКаталог(КаталогРаспаковки);

	Чтение = Новый ЧтениеZipФайла(ИмяАрхива, Пароль);
	Извлеченные = Новый Массив;

	Для Каждого Элемент Из Чтение.Элементы Цикл
		Если СтрЗаканчиваетсяНа(НРег(Элемент.Имя), ".xml") Тогда
			Чтение.Извлечь(Элемент, КаталогРаспаковки,
				РежимВосстановленияПутейФайловZIP.НеВосстанавливать);
			Извлеченные.Добавить(КаталогРаспаковки + Элемент.Имя);
		КонецЕсли;
	КонецЦикла;

	Чтение.Закрыть();
	УдалитьФайлы(ИмяАрхива);

	Возврат Извлеченные;

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

Что здесь важно:

  1. Элемент.Имя — только имя файла, Элемент.ПолноеИмя — путь внутри архива. Если в коллекции окажутся записи каталогов, проверка расширения их отсечёт.
  2. ИзвлечьВсе(Каталог, РежимВосстановленияПутейФайловZIP.Восстанавливать) распакует архив целиком со структурой папок.
  3. Закрыть() вызывайте до удаления файла архива. Пока объект чтения держит файл, УдалитьФайлы() его не удалит.
  4. У элемента есть признак Зашифрован. По нему видно, нужен ли пароль, ещё до попытки извлечения.

Архив от внешнего контрагента может содержать имена вида ..\..\файл. Распаковывайте только в отдельный временный каталог, а не в рабочие папки сервера, и проверяйте ПолноеИмя элементов перед ИзвлечьВсе().

После обработки удалите и каталог распаковки: УдалитьФайлы(КаталогРаспаковки).

Архивация в памяти: потоки и двоичные данные

Временные файлы на диске — самый совместимый путь, но не единственный. С 8.3.9 в платформе есть потоки: ПотокВПамяти, ФайловыйПоток, методы ОткрытьПотокДляЧтения() у двоичных данных.

В актуальных версиях 8.3 ЧтениеZipФайла принимает поток вместо имени файла. Это позволяет прочитать состав архива из присоединённого файла или из ответа HTTP-сервиса без записи на диск:

Поток = ДанныеАрхива.ОткрытьПотокДляЧтения();
Чтение = Новый ЧтениеZipФайла(Поток);
Для Каждого Элемент Из Чтение.Элементы Цикл
	// проверка состава архива
КонецЦикла;
Чтение.Закрыть();
Поток.Закрыть();

Извлечение всё равно пишет файлы в каталог, поэтому для распаковки диск нужен в любом случае.

Как не упереться в память сервера:

  • 🧠 ДвоичныеДанные целиком лежат в оперативной памяти рабочего процесса. Архив на 2 ГБ, прочитанный так, съест 2 ГБ и больше.
  • 🗂️ Для больших объёмов работайте с файлами на диске и не читайте архив в ДвоичныеДанные без нужды.
  • 📏 Временное хранилище тоже держит данные в памяти. Большие архивы лучше отдавать частями или выкладывать в общую папку.
  • 🧹 Каждый открытый поток закрывайте методом Закрыть(), иначе файл останется заблокированным до конца сеанса.

Если архив отправляется по HTTP или почтой, размер обычно ограничен с той стороны. Проверьте Размер() у полученных двоичных данных до отправки и разбейте выгрузку на несколько архивов, если лимит превышен.

Архивация файлов по расписанию

Частая практическая задача — раз в сутки упаковывать файлы обмена, выгрузки или сканы за прошлый день и складывать архив в отдельную папку. Для этого подходит регламентное задание с процедурой в общем модуле на сервере.

Порядок такой:

  1. В конфигураторе создайте общий модуль с флагом «Сервер» и экспортную процедуру архивации.
  2. Добавьте регламентное задание и укажите в нём эту процедуру как метод.
  3. Настройте расписание, например ежедневно в 02:00, когда пользователей в базе мало.
  4. В процедуре отберите файлы через НайтиФайлы(), упакуйте и только после успешного Записать() удаляйте исходники.

Имя архива удобно строить от даты, чтобы архивы не перезаписывали друг друга:

ИмяАрхива = ДобавитьРазделитель(КаталогАрхивов)
	+ "obmen_" + Формат(ТекущаяДатаСеанса() - 86400, "ДФ=yyyyMMdd") + ".zip";

При запуске 7 октября 2026 года получится obmen_20261006.zip — архив за предыдущие сутки.

Регламентное задание выполняется от имени службы сервера 1С, а не от пользователя. Каталог архивов должен быть доступен на запись учётной записи службы, иначе задание будет падать с ошибкой доступа каждую ночь.

Старые архивы тоже стоит чистить: отберите их по маске obmen_*.zip и удаляйте те, у которых ПолучитьВремяИзменения() объекта Файл старше нужного срока хранения, например 90 дней.

Обработка ошибок при сжатии и распаковке

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

ИмяАрхива = ПолучитьИмяВременногоФайла("zip");
Попытка
	Архив = Новый ЗаписьZipФайла(ИмяАрхива);
	Архив.Добавить(ПутьКФайлу, РежимСохраненияПутейZIP.НеСохранятьПути);
	Архив.Записать();
	Данные = Новый ДвоичныеДанные(ИмяАрхива);
	УдалитьФайлы(ИмяАрхива);
Исключение
	Информация = ИнформацияОбОшибке();
	ЗаписьЖурналаРегистрации("Архивация файлов", УровеньЖурналаРегистрации.Ошибка, , ,
		ПодробноеПредставлениеОшибки(Информация));
	Если Новый Файл(ИмяАрхива).Существует() Тогда
		УдалитьФайлы(ИмяАрхива);
	КонецЕсли;
	ВызватьИсключение КраткоеПредставлениеОшибки(Информация);
КонецПопытки;

Почему так:

  • в журнал регистрации уходит подробный текст со стеком, администратор найдёт его по событию «Архивация файлов»;
  • пользователю показывается короткое сообщение без технических деталей;
  • недописанный архив не остаётся во временном каталоге сервера.

Проверку Новый Файл(...).Существует() делайте до вызова Добавить() для каждого исходного файла. Сообщение «файл не найден» понятнее, чем исключение из глубины платформы.

Диагностика: выберите симптом

Частые вопросы

Можно ли добавить файл в уже существующий ZIP-архив?
Нет, ЗаписьZipФайла всегда создаёт архив заново. Чтобы дополнить архив, распакуйте его во временный каталог, положите туда новые файлы и упакуйте заново.
Работает ли архивация в веб-клиенте?
Создавать архив прямо в браузере не получится. Передайте файлы на сервер, упакуйте там и верните пользователю адрес во временном хранилище.
Как заархивировать файлы из присоединённых файлов документа?
Получите двоичные данные каждого присоединённого файла на сервере, запишите их во временный каталог под исходными именами и упакуйте каталог с режимом НеСохранятьПути.
Насколько сжимаются файлы?
Зависит от содержимого. Текст, XML и выгрузки сжимаются в разы, а PDF, JPG и сами ZIP почти не уменьшаются. Для таких файлов разумно выбрать МетодСжатияZIP.Копирование, это быстрее.
Можно ли распаковать RAR или 7z средствами 1С?
Нет, платформа работает только с ZIP. Для других форматов придётся вызывать внешний архиватор, установленный на сервере или компьютере пользователя.