Работа с ZIP-архивами в C# (.NET): полное руководство
В современной разработке на платформе .NET работа с архивами — одна из частых задач. Будь то упаковка логов, распаковка конфигураций или создание резервных копий — встроенные средства System.IO.Compression позволяют делать это эффективно и без сторонних библиотек. В этой статье мы разберём основные операции с ZIP-архивами на C#, включая сжатие, извлечение, добавление файлов и работу с потоками.
Необходимые пространства имён
Для работы с архивами в .NET используются два основных пространства имён:
using System.IO;
using System.IO.Compression;
Начиная с .NET Framework 4.5, класс ZipFile доступен в сборке System.IO.Compression.FileSystem. В .NET Core / .NET 5+ он входит в базовую библиотеку.
Создание ZIP-архива из файлов
Самый простой способ создать архив — использовать статический метод ZipFile.CreateFromDirectory. Он принимает путь к папке, путь к архиву и уровень сжатия.
string sourceFolder = @"C:\Temp\Documents";
string zipPath = @"C:\Temp\backup.zip";
// Создаём архив со сжатием Optimal
ZipFile.CreateFromDirectory(sourceFolder, zipPath, CompressionLevel.Optimal, false);
Console.WriteLine($"Архив создан: {zipPath}");
Параметры:
- sourceFolder — исходная директория;
- zipPath — путь к будущему архиву;
- CompressionLevel —
Optimal,FastestилиNoCompression; - includeBaseDirectory — если
true, в архиве будет корневая папка.
Распаковка ZIP-архива
Извлечение файлов выполняется методом ZipFile.ExtractToDirectory:
string zipPath = @"C:\Temp\backup.zip";
string extractPath = @"C:\Temp\Restored";
// Распаковываем с перезаписью существующих файлов
ZipFile.ExtractToDirectory(zipPath, extractPath, overwriteFiles: true);
Console.WriteLine("Архив распакован.");
В .NET 6+ появился параметр overwriteFiles, позволяющий перезаписывать файлы без исключения.
Добавление файлов в существующий архив
Класс ZipArchive даёт полный контроль над содержимым. Откроем архив в режиме обновления и добавим новый файл:
string zipPath = @"C:\Temp\backup.zip";
string newFile = @"C:\Temp\newDocument.txt";
using (FileStream zipStream = new FileStream(zipPath, FileMode.Open, FileAccess.ReadWrite))
using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Update))
{
// Создаём запись в архиве
ZipArchiveEntry entry = archive.CreateEntry("newDocument.txt");
using (StreamWriter writer = new StreamWriter(entry.Open()))
{
writer.Write("Это содержимое нового файла.");
}
Console.WriteLine($"Файл {newFile} добавлен в архив.");
}
Важно: при использовании ZipArchiveMode.Update архив должен быть открыт для чтения и записи.
Чтение содержимого архива без распаковки
Иногда нужно просто посмотреть, какие файлы внутри. Для этого перебираем записи архива:
string zipPath = @"C:\Temp\backup.zip";
using (FileStream zipStream = new FileStream(zipPath, FileMode.Open, FileAccess.Read))
using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Console.WriteLine($"Файл: {entry.FullName}, Размер: {entry.Length} байт");
}
}
Свойство FullName содержит путь внутри архива, включая подпапки.
Работа с потоками: сжатие и распаковка в памяти
Для сценариев, когда архив нужно передать по сети или сохранить в базу данных, удобно использовать MemoryStream:
// Сжатие строки в архив в памяти
using (MemoryStream ms = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, leaveOpen: true))
{
ZipArchiveEntry entry = archive.CreateEntry("data.txt");
using (StreamWriter writer = new StreamWriter(entry.Open()))
{
writer.Write("Hello, ZIP from memory!");
}
}
byte[] zipBytes = ms.ToArray();
Console.WriteLine($"Размер архива в памяти: {zipBytes.Length} байт");
}
Параметр leaveOpen: true оставляет поток открытым после закрытия архива.