Содержание
Формат zip — наиболее популярный формат архивации файлов и было бы странным, если бы в C# не было готовых классов для работы с zip-архивами. Все необходимые классы для работы с архивами zip в C# располагаются в пространстве имен System.IO.Compression.
Методы управления ZIP-архивами распределены по трем классам: ZipFile, ZipArchive и ZipArchiveEntry.
Класс ZipFile
Используя этот класс, мы можем создавать zip-архивы из каталогов и извлекать файлы из архива в каталог. Соответственно, основные методы этого класса следующие:
CreateFromDirectory()— создает zip-архив из каталогаExtractToDirectory()— извлекает файлы из архива в указанный каталогOpen()— открывает архив для работы с ним и возвращает объект типаZipArchiveOpenRead()— открывает архив только для чтения и возвращает объект типаZipArchive
Рассмотрим работу этих методов на примерах.
Как создать zip-архив каталога в C#?
string sourcePath = @"c:\temp\"; string targetPath = @"c:\archive";//папка должна существовать на диске ZipFile.CreateFromDirectory(sourcePath, Path.Combine(targetPath, "archive.zip"));
В результате будет создан архив, содержащий все файлы, находящиеся в каталоге sourcePath. При этом сам каталог в архив не включается (только файлы, находящиеся в нем).
Как создать zip-архив каталога, указав уровень сжатия файлов в C#?
string sourcePath = @"c:\temp\";
string targetPath = @"c:\archive";//папка должна существовать на диске
//Архив с минимальным размером
ZipFile.CreateFromDirectory(sourcePath, Path.Combine(targetPath, "archive_min.zip"), CompressionLevel.SmallestSize, false);
//Архив должен быть создан максимально быстро
ZipFile.CreateFromDirectory(sourcePath, Path.Combine(targetPath, "archive_fast.zip"), CompressionLevel.Fastest, false);
//Архив должен быть создан за оптимальное время с оптимальным размером (настройка по умолчанию)
ZipFile.CreateFromDirectory(sourcePath, Path.Combine(targetPath, "archive_optimal.zip"), CompressionLevel.Optimal, false);
//Архив создается без сжатия файлов
ZipFile.CreateFromDirectory(sourcePath, Path.Combine(targetPath, "archive_no_compress.zip"), CompressionLevel.NoCompression, false);
Console.WriteLine("Архив создан");
В данном случае, мы воспользовались перегруженной версией метода CreateFromDirectory, указав в качестве третьего параметра значение перечисления CompressionLevel, благодаря которому мы настраиваем уровень сжатия файлов и желаемую скорость сжатия. Четвертый параметр метода указывает на то, будет ли в архив включаться каталог, указанный в первом параметре или же, как в примере выше, в архив будут включаться только файлы из него.
Как распаковать zip-архив в C#?
string archiveFilePath = @"C:\temp\archive.zip"; //полный путь к файлу архива string targetFolder = @"c:\temp\";//путь к папке в которую будет распакован архиа bool overriteFiles = true; //перезаписать файлы, если они уже есть в папке нахначения ZipFile.ExtractToDirectory(archiveFilePath, targetFolder, overriteFiles);
Классы ZipArchive и ZipArchiveEntry
Класс ZipArchive представляет zip-архив с файлами, в то время как класс ZipArchiveEntry представляет отдельный файл внутри архива. Используя эти классы мы можем:
- изучать содержимое архива
- извлекать отдельные файлы из архива
- добавлять файлы в архив
- добавлять комментарии к архиву
Рассмотрим как мы можем работать с объектами типа ZipArchive и ZipArchiveEntry в C#.
Как создать объект типа ZipArchive в C#?
Чтобы создать объект типа ZipArchive для работы с zip-архивом, необходимо либо воспользоваться методами класса ZipFile, либо использовать один из конструкторов класса ZipArchive, указав в обоих случаях режим работы с архивом. Рассмотрим оба варианта.
Создание объекта ZipArchive с использованием методов ZipFile
Открыть zip-архив для чтения и записи файлов:
string archivePath = @"c:\archive\archive_min.zip"; ZipArchive archive = ZipFile.Open(archivePath, ZipArchiveMode.Update);
Открыть zip-архив только на чтение:
string archivePath = @"c:\archive\archive_min.zip"; ZipArchive archive = ZipFile.OpenRead(archivePath);
Второй параметр метода Open — это перечисление типа ZipArchiveMode, для которого определены следующие значения:
public enum ZipArchiveMode
{
//только чтение содержимого архива
Read = 0,
//только создание архива
Create = 1,
//чтение и запись архива
Update = 2
}
Создание объекта ZipArchive с использованием конструктора
Чтобы создать объект типа ZipArchive с использованием одного из конструкторов класса, нам необходимо передать в конструктор поток (Stream), содержащий данные архива. Например:
string archivePath = @"c:\archive\archive_min.zip"; using var fileStream = File.Open(archivePath,FileMode.Open); ZipArchive archive = new ZipArchive(fileStream); //ИЛИ ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Update);
Как перечислить все файлы, находящиеся в zip-архиве?
После того, как создан объект типа ZipArchive мы можем работать с его свойствами и методами. Перечислим все файлы, находящиеся в zip-архиве:
string archivePath = @"c:\archive\archive_min.zip";
using var fileStream = File.Open(archivePath,FileMode.Open);
ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Update);
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.Name != "")
Console.WriteLine($"Имя файла: {entry.Name} Размер сжатого файла: {entry.CompressedLength} Контрольная сумма: {entry.Crc32}");
else
Console.WriteLine($"Папка: {entry.FullName}");
}
Здесь мы перечислили все элементы архива и вывели информацию о них в консоль. В консоль будет отправлен примерно такой вывод:
Имя файла: data.txt Размер сжатого файла: 132 Контрольная сумма: 4267209921
Имя файла: debug.log Размер сжатого файла: 1205 Контрольная сумма: 3194343811
Имя файла: 002.jpg Размер сжатого файла: 589355 Контрольная сумма: 3407861831
Имя файла: data.txt Размер сжатого файла: 132 Контрольная сумма: 4267209921
Папка: debug/debug/
Имя файла: debug.log Размер сжатого файла: 1205 Контрольная сумма: 3194343811
Стоит обратить внимание на то, что папки (каталоги) также отражаются в коллекции Entries архива, но, в отличие от файлов не содержат свойств размера и имени (только свойство FullName)
Как получить детальную информацию о файле из zip-архива?
Попробуем найти в архиве определенный файл и вывести всю доступную информацию о нем в консоль.
string archivePath = @"c:\archive\archive_min.zip";
using var fileStream = File.Open(archivePath,FileMode.Open);
ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Update);
string fileName = "debug.log";
var file = archive.Entries.Where(s=>s.Name == fileName).FirstOrDefault();
if (file != null)
{
Console.WriteLine($"Имя: {file.Name}");
Console.WriteLine($"Полный путь в архиве: {file.FullName}");
Console.WriteLine($"Размер файла: {file.Length}");
Console.WriteLine($"Размер файла в сжатом состоянии: {file.CompressedLength}");
Console.WriteLine($"Контрольная сумма CRC32: {file.Crc32}");
Console.WriteLine($"Файл зашифрован: {file.IsEncrypted}");
Console.WriteLine($"Комментарий к файлу: {file.Comment}");
}
Здесь мы воспользовались методом LINQ Where для поиска необходимого файла в коллекции Entries и, затем, перечислили все доступные свойства объекта ZipArchiveEntry. Результат в консоли будет следующим:
Размер файла: 10579
Размер файла в сжатом состоянии: 1205
Контрольная сумма CRC32: 3194343811
Файл зашифрован: False
Комментарий к файлу:
Как извлечь определенный файл из zip-архива?
Для того, чтобы извлечь определенный файл из архива, мы должны воспользоваться методом ExtractToFile объекта ZipArchiveEntry. Например
string archivePath = @"c:\archive\archive_min.zip";
using var fileStream = File.Open(archivePath,FileMode.Open);
ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Update);
string fileName = "dump.sql";
var file = archive.GetEntry(fileName);
if (file != null)
{
file.ExtractToFile(Path.Combine(@"C:\archive", fileName));
}
В этом примере мы уже не пользовались LINQ для поиска файла, а использовали метод класса ZipArchive.GetEntry и, затем, извлекли найденный файл из архива в указанную папку.
Как добавить новый файл в существующий zip-архив?
Ниже представлен один из примеров того, как добавить новый файл в существующий zip-архив
string archivePath = @"c:\archive\archive_min.zip"; using var fileStream = File.Open(archivePath,FileMode.Open); using ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Update); string filePath = @"C:\archive\config.ini"; string archiveEntryName = "data.ini"; //создаем новый элемент архива archive.CreateEntryFromFile(filePath, archiveEntryName);
используя класс ZipFile, ту же самую операцию можно сделать немного короче:
string archivePath = @"c:\archive\archive_min.zip"; using ZipArchive archive = ZipFile.Open(archivePath, ZipArchiveMode.Update); string filePath = @"C:\archive\config.ini"; string archiveEntryName = "data.ini"; //создаем новый элемент архива archive.CreateEntryFromFile(filePath, archiveEntryName);
Итого
Для работы с zip-файлами в C# предназначены три класса — ZipFile, ZipArchive и ZipArchiveEntry. Используя эти классы мы можем создавать архивы из каталогов на диске, получать детальную информацию о файлах, находящихся в zip-архиве, добавлять или удалять файлы zip-архива, добавлять или удалять комментарии как к архиву в целом, так и для отдельных элементов (файлов) в zip-архиве.