При автоматизации процессов, например, при обмене документами с операторами ЭДО, часто возникает задача архивации файлов непосредственно из 1С. Популярным решением является вызов внешнего архиватора 7-Zip через объект WshShell. Однако, когда файлы для архивации находятся в глубоко вложенных папках на сетевых ресурсах, командная строка с полными путями становится громоздкой и вызывает опасения по поводу ограничений на ее длину. Рассмотрим, как решить эту задачу надежно и элегантно.
Проанализируем ситуацию: есть структура папок на сервере, в каждой из которых лежит несколько файлов. Необходимо для каждой папки создать ZIP-архив с файлами из этой же папки. Основной вопрос — как сформировать команду для WshShell.Run, чтобы она была короткой, понятной и надежной.
Это наиболее правильный и эффективный способ для работы с внешними программами. Суть подхода заключается в том, чтобы перед запуском архиватора указать ему, в какой папке он должен работать. Тогда в самой командной строке можно будет использовать относительные пути или просто имена файлов, что кардинально сокращает ее длину.
Способ А: Установка свойства WshShell.CurrentDirectory
Объект WScript.Shell, который мы создаем в 1С, имеет свойство CurrentDirectory. Оно позволяет установить текущий рабочий каталог для всех последующих команд, выполняемых через этот объект. Это идеальное решение нашей задачи.
Посмотрим на пример:
WshShell.CurrentDirectory путь к папке, где лежат наши файлы и где должен быть создан архив.
// Путь к папке с файлами для архивации
ПутьКПапке = "\\server1c\obmen_edo\doc1231\";
// Создаем COM-объект
Попытка
WshShell = Новый COMОбъект("WScript.Shell");
Исключение
Сообщить("Не удалось создать COM-объект WScript.Shell. Проверьте настройки безопасности.");
Возврат;
КонецПопытки;
// Устанавливаем текущий (рабочий) каталог.
// Это ключевой момент для сокращения команды!
WshShell.CurrentDirectory = ПутьКПапке;
// Формируем короткую и понятную команду
// 7-Zip будет искать файлы в каталоге, который мы установили выше
ИмяАрхива = "doc1231.zip";
ИменаФайлов = "file1.xml file2.xml"; // Здесь могут быть все нужные файлы через пробел
ПутьКАрхиватору = "C:\Program Files\7-Zip\7za.exe"; // Укажите ваш путь или убедитесь, что он в PATH
Кавычки = Символ(34);
Команда = Кавычки + ПутьКАрхиватору + Кавычки + " a -tzip " + ИмяАрхива + " " + ИменаФайлов;
// Запускаем команду.
// Второй параметр 0 - окно не будет показано.
// Третий параметр Истина - 1С будет ждать завершения выполнения команды.
КодВозврата = WshShell.Run(Команда, 0, Истина);
Если КодВозврата <> 0 Тогда
Сообщить("Архивация завершилась с ошибкой. Код возврата: " + КодВозврата);
КонецЕсли;
Этот метод решает исходную проблему полностью: командная строка получается короткой, а код — читаемым и легко поддерживаемым.
Способ Б: Использование ключа -w в 7-Zip
Сам архиватор 7-Zip предоставляет возможность указать рабочий каталог через специальный ключ командной строки -w. Это альтернативный вариант, если по каким-либо причинам изменять CurrentDirectory у объекта WshShell нежелательно.
Команда будет выглядеть следующим образом:
ПутьКПапке = "\\server1c\obmen_edo\doc1231\";
ИмяАрхива = "doc1231.zip";
ИменаФайлов = "file1.xml file2.xml";
ПутьКАрхиватору = "C:\Program Files\7-Zip\7za.exe";
Кавычки = Символ(34);
// Ключ -w указывается в конце и говорит 7-Zip, где нужно работать
Команда = Строка(
СтрШаблон("%1 a -tzip %2 %3 -w%4",
Кавычки + ПутьКАрхиватору + Кавычки,
ИмяАрхива,
ИменаФайлов,
Кавычки + ПутьКПапке + Кавычки
)
);
WshShell = Новый COMОбъект("WScript.Shell");
WshShell.Run(Команда, 0, Истина);
Результат будет тем же, что и в предыдущем способе. 7-Zip сам сменит свой рабочий каталог на указанный и выполнит все операции относительно него.
Если по каким-то причинам первые два способа не подходят, можно использовать полные пути. Разберем опасения, связанные с этим подходом.
Ограничение длины командной строки
Основное беспокойство автора темы было связано с возможным превышением лимита на длину командной строки. На самом деле, это опасение в большинстве случаев преувеличено. В современных версиях Windows (начиная с Windows XP/Server 2003) максимальная длина командной строки составляет 8191 символ. Этого более чем достаточно для архивации нескольких десятков файлов даже с очень длинными UNC-путями. В примере из форума была показана строка, которая успешно обрабатывалась системой, хотя и выглядела громоздко. Поэтому, если файлов не сотни, можно смело использовать полные пути.
Использование списка файлов (@fileslist.txt)
Для ситуаций с очень большим количеством файлов (сотни или тысячи) существует надежный и масштабируемый метод — передача списка файлов архиватору через текстовый файл. Это также помогает "укоротить" саму команду.
Разберем по шагам:
ТекстовыйДокумент.fileslist.txt) в той же папке.@.
Кавычки = Символ(34);
ПутьКПапке = "\\server1c\obmen_edo\doc1231\";
ИмяФайлаСписка = ПутьКПапке + "fileslist.txt";
ИмяАрхива = ПутьКПапке + "doc1231.zip";
ПутьКАрхиватору = "C:\Program Files\7-Zip\7za.exe";
// Создаем список файлов
СписокФайлов = Новый Массив;
СписокФайлов.Добавить(ПутьКПапке + "file1.xml");
СписокФайлов.Добавить(ПутьКПапке + "file2.xml");
// ... добавляем остальные файлы
ТекстовыйДокумент = Новый ТекстовыйДокумент;
Для Каждого ПолныйПуть Из СписокФайлов Цикл
ТекстовыйДокумент.ДобавитьСтроку(Кавычки + ПолныйПуть + Кавычки);
КонецЦикла;
// Записываем список во временный файл
ТекстовыйДокумент.Записать(ИмяФайлаСписка, КодировкаТекста.UTF8);
// Формируем команду с использованием файла-списка
Команда = СтрШаблон("%1 a -tzip %2 @%3",
Кавычки + ПутьКАрхиватору + Кавычки,
Кавычки + ИмяАрхива + Кавычки,
Кавычки + ИмяФайлаСписка + Кавычки
);
// Выполняем
WshShell = Новый COMОбъект("WScript.Shell");
WshShell.Run(Команда, 0, Истина);
// Удаляем временный файл
УдалитьФайлы(ИмяФайлаСписка);
Зависимость от внешнего ПО, такого как 7-Zip, имеет свои недостатки: программа должна быть установлена на сервере или клиенте, где выполняется код, и ее путь должен быть известен. Платформа 1С предлагает встроенные инструменты, которые лишены этих недостатков.
Встроенный объект ЗаписьZipФайла (ZipАрхиватор)
Начиная с платформы 8.3.6, в 1С появился встроенный объект для работы с ZIP-архивами. Это наиболее предпочтительный и надежный способ для новых разработок.
Преимущества:
Посмотрим на пример, решающий ту же задачу:
ПутьКПапке = "\\server1c\obmen_edo\doc1231\";
ИмяАрхива = ПутьКПапке + "doc1231.zip";
// Создаем объект для записи в ZIP-файл
Попытка
ЗаписьАрхива = Новый ЗаписьZipФайла(ИмяАрхива);
Исключение
Сообщить("Не удалось создать файл архива: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Добавляем файлы в архив
ЗаписьАрхива.Добавить(ПутьКПапке + "file1.xml");
ЗаписьАрхива.Добавить(ПутьКПапке + "file2.xml");
// ... и так далее для всех файлов
// Завершаем создание архива и сохраняем его на диск
ЗаписьАрхива.Записать();
Сообщить("Архив успешно создан: " + ИмяАрхива);
Как видим, код получается очень лаконичным и не требует никаких "танцев с бубном" вокруг командной строки. Если ваша конфигурация работает на платформе 8.3.6 или новее, настоятельно рекомендуется использовать именно этот метод.