Как программно скачать и распаковать архив (ZIP, 7z, RAR) в 1С:Предприятие 7.7

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

В процессе интеграции 1С:Предприятия 7.7 с внешними информационными системами часто возникает задача автоматического импорта данных. Распространенный сценарий: скачать архив с файлом данных (например, в формате .zip, .7z или .rar) по протоколу HTTP/HTTPS, распаковать его во временный каталог и загрузить содержимое в базу данных. В этой статье мы подробно разберем, как решить эту задачу на платформе 1С 7.7, исправим критические ошибки популярных решений и рассмотрим альтернативные варианты реализации.

Выясним причину: почему встроенный архиватор отсутствует в 1С 7.7

Проанализируем возможности самой платформы. Начинающие разработчики часто ищут в Синтакс-Помощнике 1С 7.7 объекты для работы с архивами, аналогичные тем, что есть в современных версиях 1С (например, ЗаписьZipФайла и ЧтениеZipФайла). Однако в платформе 1С 7.7 нет встроенных программных средств для работы с ZIP-архивами на уровне встроенного языка. Эти объекты появились только начиная с платформы 1С:Предприятие 8.1.

Хотя сама платформа 7.7 умеет создавать резервные копии базы данных в формате ZIP, доступ к этим механизмам для разработчиков закрыт. Поэтому для решения задачи нам придется использовать сторонние инструменты. Рассмотрим по шагам каждый из возможных вариантов: от внешних компонент до штатных механизмов операционной системы Windows.

Разберем по шагам: корректное скачивание бинарных файлов по HTTP

Прежде чем распаковывать архив, его необходимо скачать. В исходном обсуждении на форуме предлагается использовать объект WinHttp.WinHttpRequest.5.1, однако в коде допущена критическая ошибка: ответ сервера считывается как текст через свойство ResponseText и записывается на диск с помощью объекта Текст.

Важное предупреждение: Попытка скачать бинарный файл (архив, картинку, исполняемый файл) как текст неизбежно приведет к его повреждению! Текстовый объект 1С преобразует нулевые байты и спецсимволы в соответствии с кодовой страницей Windows, что нарушает внутреннюю структуру архива. В результате распаковать такой архив будет невозможно.

Чтобы избежать повреждения данных, мы должны получать ответ сервера как двоичные данные (свойство ResponseBody) и сохранять их с помощью COM-объекта ADODB.Stream. Посмотрим на пример правильной реализации функции скачивания:


Функция СкачатьАрхивПоHTTP(АдресРесурса, ПутьСохранения, СтрОшибка)
    Попытка
        wHTTP = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
        wHTTP.Open("GET", АдресРесурса, 0); // 0 = синхронный режим
        wHTTP.Send();
    Исключение
        СтрОшибка = "Ошибка при отправке запроса: " + ОписаниеОшибки();
        Возврат 0;
    КонецПопытки;

    Если wHTTP.Status <> 200 Тогда
        СтрОшибка = "Сервер вернул код ответа: " + wHTTP.Status + " " + wHTTP.StatusText;
        Возврат 0;
    КонецЕсли;

    // Запись бинарных данных на диск через ADODB.Stream
    Попытка
        Stream = СоздатьОбъект("ADODB.Stream");
        Stream.Type = 1; // 1 = adTypeBinary (бинарный режим)
        Stream.Mode = 3; // 3 = adModeReadWrite (разрешено чтение и запись)
        Stream.Open();
        Stream.Write(wHTTP.ResponseBody); // Записываем массив байт в поток
        Stream.SaveToFile(ПутьСохранения, 2); // 2 = перезаписать файл, если он существует
        Stream.Close();
    Исключение
        СтрОшибка = "Не удалось сохранить файл на диск: " + ОписаниеОшибки();
        Возврат 0;
    КонецПопытки;

    Возврат 1;
КонецФункции

Обратите внимание: использование устаревшей библиотеки V7Plus.dll и ее объекта AddIn.V7HttpReader в современных реалиях не рекомендуется. Этот компонент не поддерживает протоколы безопасности TLS 1.2/1.3, которые сегодня требуются на большинстве веб-серверов, и часто дает сбой (скачивает файл не полностью), если сервер не передает заголовок Content-Length.

Способ №1: Использование внешних компонент (DialMail.dll и 1С++)

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

Вариант А: Распаковка через DialMail.dll

Компонента DialMail.dll традиционно использовалась в 1С 7.7 для работы с почтой, но в ней также есть отличный модуль для работы с ZIP-архивами. Посмотрим на пример кода распаковки:


Функция РаспаковатьЧерезDialMail(ПутьКАрхиву, КаталогРаспаковки, СтрОшибка)
    Если ЗагрузитьВнешнююКомпоненту("DialMail.dll") = 0 Тогда
        СтрОшибка = "Не удалось загрузить компоненту DialMail.dll!";
        Возврат 0;
    КонецЕсли;

    Попытка
        Архиватор = СоздатьОбъект("AddIn.ZIP");
    Исключение
        СтрОшибка = "Не удалось создать объект AddIn.ZIP!";
        Возврат 0;
    КонецПопытки;

    Если Архиватор.УстановитьАрхивТекущим(СокрЛП(ПутьКАрхиву)) = 0 Тогда
        СтрОшибка = "Ошибка чтения архива или файл поврежден.";
        Возврат 0;
    КонецЕсли;

    Архиватор.КаталогИзвлечения = КаталогРаспаковки;
    КоличествоФайлов = Архиватор.КоличествоФайлов;

    Если КоличествоФайлов = 0 Тогда
        СтрОшибка = "Архив пуст!";
        Возврат 0;
    КонецЕсли;

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

    Возврат 1;
КонецФункции

Вариант Б: Распаковка через 1С++ (1CPP.dll)

Если в вашей конфигурации уже используется легендарная внешняя компонента 1С++, вам доступен класс BinaryData, который позволяет запаковывать и распаковывать ZIP буквально в одну строку кода:


Функция РаспаковатьЧерез1СПП(ПутьКАрхиву, КаталогРаспаковки, СтрОшибка)
    Если ЗагрузитьВнешнююКомпоненту("1cpp.dll") = 0 Тогда
        СтрОшибка = "Компонента 1С++ не установлена!";
        Возврат 0;
    КонецЕсли;

    Попытка
        БД = СоздатьОбъект("BinaryData");
        // Метод UnZip распаковывает архив в указанный каталог
        БД.UnZip(ПутьКАрхиву, КаталогРаспаковки);
    Исключение
        СтрОшибка = "Ошибка распаковки: " + ОписаниеОшибки();
        Возврат 0;
    КонецПопытки;

    Возврат 1;
КонецФункции

Способ №2: Работа с консольными архиваторами (7-Zip и WinRAR)

Если внешние компоненты использовать нежелательно, мы можем задействовать консольные утилиты архиваторов, которые часто уже установлены на компьютерах пользователей или могут быть положены прямо в каталог базы данных (например, бесплатная консольная версия 7-Zip — 7za.exe).

В исходном сообщении №4 для запуска утилит используется стандартный метод 1С КомандаСистемы(). У этого метода есть существенные недостатки: во-первых, на экране пользователя на время работы архиватора всегда "мигает" черное окно командной строки Windows; во-вторых, код 1С не может корректно дождаться окончания работы утилиты, если не использовать сложные костыли с файлами-флагами.

Решение проблемы: Использование COM-объекта WScript.Shell и его метода Run. Данный метод позволяет запустить любую консольную команду в фоновом (скрытом) режиме и приостановить выполнение кода 1С до завершения работы внешней программы.

Рассмотрим пример использования консольной утилиты 7za.exe с невидимым запуском:


Функция РаспаковатьКонсольным7Zip(ПутьКАрхиву, КаталогРаспаковки, СтрОшибка)
    ПутьКУтилите = КаталогИБ() + "ExtForms\7zip\7za.exe";
    Если ФС.СуществуетФайл(ПутьКУтилите) = 0 Тогда
        СтрОшибка = "Отсутствует исполняемый файл утилиты 7za.exe по пути: " + ПутьКУтилите;
        Возврат 0;
    КонецЕсли;

    // Формируем параметры запуска утилиты:
    // e - команда распаковки (извлечь файлы в текущую папку без путей)
    // -o - указание выходного каталога (без пробела перед путем!)
    // -y - отвечать "Да" на все запросы (например, на замену файлов)
    ТекстКоманды = """" + ПутьКУтилите + """ e """ + ПутьКАрхиву + """ -o""" + КаталогРаспаковки + """ -y";

    Попытка
        WshShell = СоздатьОбъект("WScript.Shell");
        // Параметры метода Run:
        // 1-й: Строка запуска
        // 2-й: 0 - скрыть окно командной строки (полная невидимость)
        // 3-й: 1 (Истина) - ожидать завершения процесса перед возвратом в 1С
        КодВозврата = WshShell.Run(ТекстКоманды, 0, 1);
    Исключение
        СтрОшибка = "Не удалось запустить утилиту распаковки: " + ОписаниеОшибки();
        Возврат 0;
    КонецПопытки;

    Если КодВозврата <> 0 Тогда
        СтрОшибка = "Архиватор завершил работу с ошибкой. Код возврата: " + КодВозврата;
        Возврат 0;
    КонецЕсли;

    Возврат 1;
КонецФункции

Способ №3: Использование Windows Shell.Application (без внешних файлов)

Если вам запрещено копировать в каталог базы внешние .exe файлы вроде 7za.exe и регистрировать внешние компоненты, можно использовать встроенную службу проводника Windows через COM-объект Shell.Application. Этот способ работает "из коробки" на любой операционной системе Windows.

Однако здесь программиста подстерегают два очень важных подводных камня:

  1. Асинхронность копирования: Метод CopyHere запускает процесс извлечения файлов в фоновом режиме операционной системы. Строка кода в 1С завершится мгновенно, но файлы на диске появятся лишь через некоторое время. Если сразу после вызова метода попытаться открыть файл, 1С выдаст ошибку "Файл не найден". Нам потребуется организовать цикл ожидания.
  2. Всплывающие диалоги: При возникновении ошибок или конфликтов имен Windows по умолчанию выводит интерактивные окна с вопросами к пользователю. Чтобы это отключить, нужно использовать специальные флаги.

Проанализируем пример кода распаковки ZIP с решением этих проблем:


Функция РаспаковатьЧерезShellApplication(ПутьКАрхиву, КаталогРаспаковки, СтрОшибка)
    Попытка
        Shell = СоздатьОбъект("Shell.Application");
    Исключение
        СтрОшибка = "Не удалось запустить службу Shell.Application";
        Возврат 0;
    КонецПопытки;

    // В Shell.Application пути обязательно должны быть полными и корректными объектами папок
    Попытка
        ОбъектАрхива = Shell.NameSpace(ПутьКАрхиву);
        ОбъектНазначения = Shell.NameSpace(КаталогРаспаковки);
    Исключение
        СтрОшибка = "Ошибка доступа к путям через Shell.Application";
        Возврат 0;
    КонецПопытки;

    Если (ОбъектАрхива Есть Ничего) Или (ОбъектНазначения Есть Ничего) Тогда
        // На случай, если COM-объекты вернули пустоту из-за неверных путей
        СтрОшибка = "Не удалось инициализировать папки архива или назначения.";
        Возврат 0;
    КонецЕсли;

    // Получаем элементы архива
    ЭлементыАрхива = ОбъектАрхива.Items();
    КоличествоЭлементов = ЭлементыАрхива.Count;

    Если КоличествоЭлементов = 0 Тогда
        СтрОшибка = "Архив пуст.";
        Возврат 0;
    КонецЕсли;

    // Флаги копирования:
    // 4 - не показывать индикатор прогресса Windows
    // 16 - автоматически отвечать "Да для всех" на любые вопросы системы
    // 512 - не подтверждать создание новых каталогов
    // 1024 - не показывать окна ошибок
    ФлагиОпций = 4 + 16 + 512 + 1024;

    // Запускаем извлечение
    ОбъектНазначения.CopyHere(ЭлементыАрхива, ФлагиОпций);

    // Боремся с асинхронностью: организуем цикл ожидания появления файлов на диске
    WshShell = СоздатьОбъект("WScript.Shell");
    Попытка
        ФС = СоздатьОбъект("ФС");
    Исключение
        // Используем базовые механизмы, если объект ФС недоступен в данном контексте
    КонецПопытки;

    СчетчикОжидания = 0;
    МаксимальноеОжидание = 60; // Ждем максимум 60 секунд

    Пока ОбъектНазначения.Items().Count < КоличествоЭлементов Цикл
        // Делаем паузу в 1 секунду, чтобы не вешать процессор бесконечным циклом
        // Для этого используем пинг локального хоста (штатный трюк в 1С 7.7)
        WshShell.Run("ping -n 2 127.0.0.1", 0, 1);
        
        СчетчикОжидания = СчетчикОжидания + 1;
        Если СчетчикОжидания > МаксимальноеОжидание Тогда
            СтрОшибка = "Превышено время ожидания распаковки архива.";
            Возврат 0;
        КонецЕсли;
    КонецЦикла;

    Возврат 1;
КонецФункции

Способ №4: Современная альтернатива для современных Windows — PowerShell

Если ваши пользователи работают на операционных системах Windows 7 SP1, Windows 10 или Windows 11, у вас есть доступ к мощному инструменту автоматизации — PowerShell. Начиная с версии PowerShell 5.0, в системе присутствуют встроенные быстрые командлеты для архивации, которые работают без внешних утилит, без асинхронных задержек и не показывают пользователю никаких всплывающих окон.

Рассмотрим, как запустить распаковку через PowerShell из кода 1С 7.7:


Функция РаспаковатьЧерезPowerShell(ПутьКАрхиву, КаталогРаспаковки, СтрОшибка)
    // Командлет Expand-Archive распаковывает архив
    // Параметр -Force разрешает перезапись уже существующих файлов
    ТекстКоманды = "powershell -Command ""Expand-Archive -Path '" + ПутьКАрхиву + "' -DestinationPath '" + КаталогРаспаковки + "' -Force""";

    Попытка
        WshShell = СоздатьОбъект("WScript.Shell");
        // Запуск в скрытом режиме (0) с обязательным ожиданием окончания работы (1)
        КодВозврата = WshShell.Run(ТекстКоманды, 0, 1);
    Исключение
        СтрОшибка = "Ошибка запуска PowerShell: " + ОписаниеОшибки();
        Возврат 0;
    КонецПопытки;

    Если КодВозврата <> 0 Тогда
        СтрОшибка = "PowerShell завершил работу с ошибкой. Код возврата: " + КодВозврата;
        Возврат 0;
    КонецЕсли;

    Возврат 1;
КонецФункции

Подведем итоги и сравним методы

Мы рассмотрели несколько подходов к решению задачи. Какой же из них выбрать?

Выбирайте наиболее подходящий для вашей инфраструктуры метод, не забывайте корректно скачивать бинарные данные, и ваши интеграционные процессы будут работать стабильно и незаметно для пользователей!

← На главную