Распаковка ZIP-архива кодом 1С: ЧтениеZipФайла, ошибки, автоматизация

· 9 мин

Содержание

Распаковать ZIP файл в 1С можно встроенным объектом платформы ЧтениеZipФайла: открыть архив, вызвать ИзвлечьВсе(Каталог) и закрыть. Внешние архиваторы не нужны, объект есть на сервере и в толстом и тонком клиенте 1С:Предприятия 8.3.

Типичная ситуация: банк, поставщик или государственный сервис присылает выгрузку архивом, а загрузку в базу нужно сделать без ручной работы бухгалтера. Ниже код, который работает в клиент-серверном и файловом варианте, плюс разбор подводных камней: права службы, вложенные каталоги, пароль, русские имена файлов.

Что подготовить до распаковки архива

Первое, что ломает распаковку, — путаница, где выполняется код. Серверная процедура пишет файлы на диск сервера 1С, а не на компьютер пользователя.

Где окажутся файлы

Где выполняется кодЧей дискПод какой учётной записью
&НаКлиенте (тонкий/толстый клиент)компьютер пользователяпользователь Windows
&НаСервере в клиент-серверной базесервер 1Сслужба агента сервера (обычно USR1CV8, в Linux usr1cv8)
&НаСервере в файловой базекомпьютер, где запущен клиентпользователь Windows
Веб-клиентработа с ZIP только на сервереслужба веб-сервера и сервера 1С

Чек-лист окружения

  • 📁 Каталог назначения существует или создаётся кодом через СоздатьКаталог().
  • 🔐 У учётной записи службы 1С есть права на запись в этот каталог. Сетевую папку \\server\share служба под локальной учёткой не увидит.
  • 💾 Свободного места больше, чем суммарный распакованный размер. Его можно узнать заранее (см. раздел про защиту).
  • 🧹 Для промежуточных файлов берите КаталогВременныхФайлов() и ПолучитьИмяВременногоФайла(), а не жёсткий C:\Temp.

На Linux-сервере в путях разделитель /. Собирайте пути через ПолучитьРазделительПути(), тогда код не придётся переписывать при переезде сервера.

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

Распаковка ZIP встроенными средствами 1С

Основной инструмент — ЧтениеZipФайла. Его ключевые методы:

  • Открыть(ИмяФайла, Пароль) — открывает архив (можно передать имя файла прямо в конструктор).
  • ИзвлечьВсе(Каталог, РежимВосстановленияПутей) — распаковывает всё.
  • Извлечь(Элемент, Каталог, РежимВосстановленияПутей, Пароль) — распаковывает один файл.
  • Закрыть() — освобождает файл архива.

Свойство Элементы — коллекция содержимого архива: можно посмотреть список файлов, не распаковывая их.

Минимальный вариант на сервере

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

    СоздатьКаталог(КаталогНазначения);

    Архив = Новый ЧтениеZipФайла(ИмяАрхива);
    Архив.ИзвлечьВсе(КаталогНазначения, РежимВосстановленияПутейФайловZIP.ВосстанавливатьПолныеПути);
    Архив.Закрыть();

    Возврат НайтиФайлы(КаталогНазначения, ПолучитьМаскуВсеФайлы(), Истина);

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

Функция вернёт массив объектов Файл по всем распакованным файлам и папкам, включая вложенные.

Пользователь выбирает архив на своём компьютере

Архив с компьютера пользователя сначала передают на сервер через временное хранилище. Код формы:

&НаКлиенте
Процедура ЗагрузитьАрхив(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
    НачатьПомещениеФайла(Оповещение, , "", Истина, УникальныйИдентификатор);
КонецПроцедуры

&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
    Если Не Результат Тогда
        Возврат; // пользователь отменил выбор
    КонецЕсли;
    КоличествоФайлов = РаспаковатьНаСервере(Адрес);
    Сообщить("Распаковано файлов: " + Формат(КоличествоФайлов, "ЧН=0; ЧГ=0"));
КонецПроцедуры

&НаСервереБезКонтекста
Функция РаспаковатьНаСервере(Адрес)

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

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

    Архив = Новый ЧтениеZipФайла(ИмяАрхива);
    Архив.ИзвлечьВсе(Каталог, РежимВосстановленияПутейФайловZIP.ВосстанавливатьПолныеПути);
    Архив.Закрыть();
    УдалитьФайлы(ИмяАрхива);

    Найденные = НайтиФайлы(Каталог, ПолучитьМаскуВсеФайлы(), Истина);
    Количество = 0;
    Для Каждого ФайлАрхива Из Найденные Цикл
        Если ФайлАрхива.ЭтоФайл() Тогда
            Количество = Количество + 1;
            // здесь обработка файла: чтение XML, загрузка в документы и т.д.
        КонецЕсли;
    КонецЦикла;

    УдалитьФайлы(Каталог);
    Возврат Количество;

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

Этот вариант работает и в веб-клиенте: файл с машины пользователя уходит на сервер, а распаковка идёт там.

Распаковка прямо на компьютер пользователя

Иногда файлы нужны не базе, а человеку: например, распаковать присланный комплект документов в папку «Загрузки». В тонком и толстом клиенте объект ЧтениеZipФайла доступен и на клиенте, так что код можно выполнить в процедуре &НаКлиенте.

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

  1. Пользователь выбирает архив и каталог через ДиалогВыбораФайла (режимы Открытие и ВыборКаталога), вызванный немодально методом Показать.
  2. В обработчике оповещения создаётся ЧтениеZipФайла и вызывается ИзвлечьВсе в выбранный каталог.
  3. Файлы пишутся с правами пользователя Windows, служба сервера 1С в этом не участвует.

В веб-клиенте так не получится: там работа с ZIP возможна только на сервере, а результат отдают пользователю через НачатьПолучениеФайлов или аналогичные методы получения файлов.

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

Вложенные папки и структура ZIP-архива

Второй параметр ИзвлечьВсе решает, что делать с папками внутри архива.

Значение РежимВосстановленияПутейФайловZIPРезультат
ВосстанавливатьПолныеПутидерево папок воссоздаётся, подкаталоги создаются автоматически
НеВосстанавливатьвсе файлы складываются в один каталог

С НеВосстанавливать есть ловушка: если в разных подпапках лежат файлы с одним именем (2024/act.xml и 2025/act.xml), последний перезапишет предыдущий. Для выгрузок с повторяющимися именами берите полные пути.

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

Часто из архива нужен один тип файлов, например только XML. Перебирать коллекцию Элементы и извлекать нужное быстрее, чем распаковать всё и чистить лишнее:

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

У элемента полезны свойства Имя, ПолноеИмя (путь внутри архива), Путь, Расширение, НеСжатыйРазмер и Зашифрован. Расширение платформа возвращает без точки.

Мусор из архивов, созданных на macOS

Архивы, собранные на Mac, содержат служебную папку __MACOSX и файлы .DS_Store. Отсекайте их фильтром по ПолноеИмя, иначе загрузчик попытается прочитать служебный файл как XML и упадёт.

Архив внутри архива

Поставщики иногда упаковывают ZIP в ZIP. Здесь работает рекурсия: после распаковки ищем в каталоге файлы с расширением zip и для каждого вызываем ту же функцию с новым подкаталогом. Ограничьте глубину (например, 3 уровня), чтобы испорченный архив не завёл код в бесконечный цикл.

Ошибки при распаковке ZIP и защита от сбоев

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

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

Запись в журнал регистрации пригодится, когда распаковка идёт фоном и пользователь сообщения не увидит.

Проверка до распаковки

Перед ИзвлечьВсе стоит пройтись по Элементы и проверить две вещи:

  1. Пути с ... Злонамеренный архив может содержать элемент вида ../../bin/файл, который при восстановлении путей запишется за пределы каталога назначения. Если СтрНайти(Элемент.ПолноеИмя, "..") > 0, распаковку прерываем.
  2. Суммарный размер. Складываем НеСжатыйРазмер всех элементов. Архив весом 1 МБ может разворачиваться в десятки гигабайт и забить диск сервера. Задайте разумный потолок под ваши данные, например 500 МБ, и сравнивайте с ним.

Архивы из внешних источников (почта, сайты, загрузка пользователем) распаковывайте только после этих двух проверок.

Разбор частых сбоев

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

Контроль результата

После распаковки полезно сверить итог с содержимым архива. Простая проверка: число элементов-файлов в Архив.Элементы равно числу файлов, которые вернул НайтиФайлы по каталогу назначения. Если числа не сходятся, часть файлов не записалась (нет места, длинный путь, запрещённые символы в имени).

На Windows отдельно помните про длину пути. Глубоко вложенная структура архива плюс длинный путь каталога назначения легко превышают 260 символов, и такие файлы не создаются. Распаковывайте в короткий каталог вроде C:\Z\ или во временный каталог службы.

Автоматизация распаковки через внешнюю обработку

Чтобы не трогать типовую конфигурацию , распаковку оформляют внешней обработкой (.epf). Порядок такой:

  1. В конфигураторе: Файл → Новый → Внешняя обработка.
  2. Добавьте реквизиты ПутьКАрхиву и КаталогНазначения (тип «Строка»), создайте управляемую форму.
  3. Вынесите на форму команду «Распаковать» и вставьте код из раздела выше: клиентская часть выбирает файл, серверная распаковывает.
  4. Сохраните обработку и откройте её в пользовательском режиме через Файл → Открыть.

Распаковка по расписанию

Если архивы приходят регулярно в один каталог (например, банк кладёт выписки на файловый ресурс), удобно разбирать их без человека. В типовых конфигурациях на БСП для этого есть механизм дополнительных обработок: в БП 3.0 он включается в Администрирование → Печатные формы, отчеты и обработки флажком «Дополнительные отчеты и обработки».

Обработку регистрируют как дополнительную, а для её серверной команды задают расписание. Внутри команды:

  • 🔎 НайтиФайлы(КаталогВходящих, "*.zip") собирает новые архивы;
  • 📦 каждый распаковывается во временный каталог с проверками из прошлого раздела;
  • 📄 файлы загружаются в базу;
  • 🗂️ обработанный архив переносится в папку «Архив» через ПереместитьФайл(), чтобы не разобрать его повторно.

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

1С или 7-Zip: какой способ распаковки выбрать

Встроенный объект закрывает большинство задач. Внешний архиватор нужен, когда приходит не ZIP или когда стандартный разбор спотыкается о кодировку.

СпособКогда подходитОграничения и риски
ЧтениеZipФайлаобычные ZIP-архивы, работа в веб-клиенте, на сервере Linux и Windowsтолько формат ZIP; кодировка старых архивов
7-Zip через ЗапуститьПриложениеRAR, 7z, многотомные архивы, проблемные имена файлов7-Zip должен быть установлен на той машине, где выполняется код
unzip на Linux-серверебыстрая распаковка больших архивов на серверепакет нужно поставить на сервер; права пользователя usr1cv8
Ручная распаковка в проводникеразовая задачане автоматизируется

Вызов 7-Zip из кода

КодВозврата = 0;
Команда = """C:\Program Files\7-Zip\7z.exe"" x """ + ИмяАрхива + """ -o""" + Каталог + """ -y";
ЗапуститьПриложение(Команда, , Истина, КодВозврата);
Если КодВозврата > 1 Тогда
    ВызватьИсключение "7-Zip завершился с ошибкой, код " + Формат(КодВозврата, "ЧН=0; ЧГ=0");
КонецЕсли;

Ключ x распаковывает с сохранением папок, -o задаёт каталог (пишется слитно с путём), -y отвечает «да» на перезапись. Код возврата 0 означает успех, 1 — предупреждение, 2 и выше — ошибку.

Для Linux аналог: unzip -o архив.zip -d /tmp/out.

Не подставляйте в команду имя файла, пришедшее извне, без проверки: символы & и " в имени превращают строку в другую команду. Безопаснее сначала сохранить архив под своим именем из ПолучитьИмяВременногоФайла("zip").

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

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