Многие .Net разработчики в своих проектах сталкиваются с задачей архивирования файлов. Наилучшие показатели по сжатию на текущий момент принадлежат архиватору 7-zip. Поэтому именно его будем использовать для сжатия файлов в наших .Net приложениях. К тому же он бесплатный :)
Последнюю версию 7-zip можно загрузить .
Мы будем использовать 7-zip, запуская его с помощью ProcessStartInfo из сборки System.Diagnostics. Этот класс позволяет задавать набор аргументов командной строки при запуске процесса.
7-zip после своей работы может вернуть одно из следующих значений:
0 – без ошибок;
1 - некритичное предупреждение. Например, один или несколько файлов заблокированы другим процессом. 7-zip отработает, но эти файлы положит в архив в несжатом виде;
2 – Фатальная ошибка;
7 - Ошибка в командной строке;
8 - Недостаточно памяти для выполнения операции;
255 - Пользователь отменил выполнение операции.
В нашем C# проекте будем отлавливать код завершения 7-zip. Если операция архивирования или извлечения из архива прошла неудачно, то дадим 7-zip еще одну попытку выполнить операцию. Ну, если уж со второго раза ничего не получилось, нужно дать знать об этом программисту, вызвав исключение с текстом ошибки.
C# 7-zip добавление в архив
Логика работы функции по добавлению файлов в 7-zip архив AddToArchive:
Проверяем наличие архиватора 7-zip;
Формируем экземпляр класса ProcessStartInfo, задаем в качестве аргументов степень сжатия, список сжимаемых файлов, имя выходного архива. Для списка файлов можно применить маску файлов, используя стандартные dos-овские обозначения (*) и (?);
Запускаем процесс 7-zip с нашими аргументами;
По завершению анализируем код завершения ExitCode;
Если нет критических ошибок, то заканчиваем работу;
Иначе через одну секунду пробуем еще раз выполнить архивацию;
При повторной неудаче генерируем исключение в зависимости от кода завершения ExitCode.
using System.Diagnostics;
/// <summary>
/// Создает архив archiveName , содержащий файлы fileNames
/// </summary>
/// <param name="archiver">файл архиватора вместе с полным путем</param>
/// <param name="fileNames">Файлы для запаковки (можно с маской *)</param>
/// <param name="archiveName">Имя архива с полным путем</param>
public static void AddToArchive(string archiver, string fileNames,
string archiveName)
{
try
{
// Предварительные проверки
if (!File.Exists(archiver))
throw new Exception("Архиватор 7z по пути \"" + archiver +
"\" не найден");
// Формируем параметры вызова 7z
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = archiver;
// добавить в архив с максимальным сжатием
startInfo.Arguments = " a -mx9 ";
// имя архива
startInfo.Arguments += "\"" + archiveName + "\"";
// файлы для запаковки
startInfo.Arguments += " \"" + fileNames + "\"";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
int sevenZipExitCode = 0;
using (Process sevenZip = Process.Start(startInfo))
{
sevenZip.WaitForExit();
sevenZipExitCode = sevenZip.ExitCode;
}
// Если с первого раза не получилось,
//пробуем еще раз через 1 секунду
if (sevenZipExitCode != 0 && sevenZipExitCode != 1)
{
using (Process sevenZip = Process.Start(startInfo))
{
Thread.Sleep(1000);
sevenZip.WaitForExit();
switch (sevenZip.ExitCode)
{
case 0: return; // Без ошибок и предупреждений
case 1: return; // Есть некритичные предупреждения
case 2: throw new Exception("Фатальная ошибка");
case 7: throw new Exception("Ошибка в командной строке");
case 8:
throw new Exception("Недостаточно памяти для выполнения операции");
case 225:
throw new Exception("Пользователь отменил выполнение операции");
default: throw new Exception("Архиватор 7z вернул
недокументированный код ошибки: " + sevenZip.ExitCode.ToString());
}
}
}
}
catch (Exception e)
{
throw new Exception("SevenZip.AddToArchive: " + e.Message);
}
}
// Пример вызова функции AddToArchive
AddToArchive(@"C:\Program Files\7-Zip\7z.exe", @"C:\archive\*.*",
@"C:\archive.7z");
// После вызова AddToArchive в архиве C:\archive.7z будут лежать файлы
//из каталога C:\archive
C# 7-zip извлечение из архива
Логика работы функции по извлечению из 7-zip архива ExtractFromArchive:
Проверяем наличие архиватора и файла 7-zip архива. Создаем выходную директорию, если ее еще нет;
Формируем экземпляр класса ProcessStartInfo, задаем в качестве аргументов имя архива и выходной каталог;
Запускаем процесс 7-zip с нашими аргументами;
По завершению анализируем код завершения ExitCode;
Если нет критических ошибок, то заканчиваем работу;
Иначе через одну секунду пробуем еще раз выполнить извлечение из архива;
При повторной неудаче генерируем исключение в зависимости от кода завершения ExitCode.
using System.Diagnostics;
/// <summary>
/// Распаковывает архив archiveName в каталог outputFolder
/// </summary>
/// <param name="archiver">файл архиватора вместе с полным путем</param>
/// <param name="archiveName">Имя архива с полным путем</param>
/// <param name="outputFolder">Каталог для распаковки</param>
public static void ExtractFromArchive(string archiver, string archiveName,
string outputFolder)
{
try
{
// Предварительные проверки
if (!File.Exists(archiver))
throw new Exception("Архиватор 7z по пути \"" + archiver +
"\" не найден");
if (!File.Exists(archiveName))
throw new Exception("Файл архива \"" + archiveName +
"\" не найден");
if (!Directory.Exists(outputFolder))
Directory.CreateDirectory(outputFolder);
// Формируем параметры вызова 7z
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = archiver;
// Распаковать (для полных путей - x)
startInfo.Arguments = " e";
// На все отвечать yes
startInfo.Arguments += " -y";
// Файл, который нужно распаковать
startInfo.Arguments += " " + "\"" + archiveName + "\"";
// Папка распаковки
startInfo.Arguments += " -o" + "\"" + outputFolder + "\"";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
int sevenZipExitCode = 0;
using (Process sevenZip = Process.Start(startInfo))
{
sevenZip.WaitForExit();
sevenZipExitCode = sevenZip.ExitCode;
}
// Если с первого раза не получилось,
//пробуем еще раз через 1 секунду
if (sevenZipExitCode != 0 && sevenZipExitCode != 1)
{
using (Process sevenZip = Process.Start(startInfo))
{
Thread.Sleep(1000);
sevenZip.WaitForExit();
switch (sevenZip.ExitCode)
{
case 0: return; // Без ошибок и предупреждений
case 1: return; // Есть некритичные предупреждения
case 2: throw new Exception("Фатальная ошибка");
case 7: throw new Exception("Ошибка в командной строке");
case 8:
throw new Exception("Недостаточно памяти для выполнения операции");
case 225:
throw new Exception("Пользователь отменил выполнение операции");
default: throw new Exception("Архиватор 7z вернул
недокументированный код ошибки: " + sevenZip.ExitCode.ToString());
}
}
}
}
catch (Exception e)
{
throw new Exception("SevenZip.ExtractFromArchive: " + e.Message);
}
}
// Пример вызова функции ExtractFromArchive
ExtractFromArchive(@"C:\Program Files\7-Zip\7z.exe", @"C:\archive.7z",
@"C:\archive");
// После вызова ExtractFromArchive в каталоге C:\archive будут лежать файлы
// из архива C:\archive.7z