База знань

Стиснення та розпакування файлів за допомогою C# – Компресія та декомпресія

Що таке ZIP (формат файлу)

ZIP – це архівний формат, який підтримує безвтратне стиснення даних. Архів ZIP може містити один або кілька файлів чи каталогів, які були стиснуті. Файли ZIP зазвичай мають розширення .zip або .ZIP і MIME‑тип application/zip. Багато програм використовують ZIP як базовий формат, часто під іншим ім’ям. У графічних інтерфейсах файли ZIP часто позначаються іконкою, що нагадує застібку‑блискавку.

Існує кілька способів стискати (компресувати) файли – залежно від операційної системи. Майже щодня нам потрібно стискати або розпаковувати файли та передавати їх на сервери чи у файлові сховища. На щастя, цей процес можна автоматизувати за допомогою Aspose.ZIP API . API дозволяє стискати та розпаковувати файли без зайвих турбот про внутрішню структуру архіву. У цій статті розглядаються приклади роботи з одним файлом і з кількома файлами одночасно.

Пакет Aspose.ZIP можна додати до вашого .NET‑проекту за допомогою наступної команди NuGet:

PM> Install-Package Aspose.Zip

Як стиснути один файл за допомогою C#

  1. Спочатку створюємо об’єкт FileStream для вихідного ZIP‑архіву.
  2. Завантажуємо один файл у FileStream.
  3. Створюємо об’єкт Archive.
  4. Додаємо файл до архіву за допомогою методу Archive.CreateEntry(“FileName”, FileStream).
  5. Зберігаємо ZIP‑архів за допомогою методу Archive.Save(FileStream).
using (FileStream zipFile = File.Open(dataDir + "CompressSingleFile_out.zip", FileMode.Create))
{
    // Файл, який додаємо до архіву
    using (FileStream source1 = File.Open(dataDir + "alice29.txt", FileMode.Open, FileAccess.Read))
    {
        using (var archive = new Archive(new ArchiveEntrySettings()))
        {
            archive.CreateEntry("alice29.txt", source1);
            archive.Save(zipFile);
        }
    }
}

Стиснення кількох файлів за допомогою C#

Різниця між стисканням одного файлу та кількох полягає в тому, що потрібно завантажити кілька файлів у FileStream і додати їх усі до ZIP‑архіву методом Archive.CreateEntry(“FileName”, FileStream). Нижче наведено приклад коду, який демонструє додавання декількох файлів.

// Створюємо FileStream для вихідного ZIP‑архіву
using (FileStream zipFile = File.Open("compressed_files.zip", FileMode.Create))
{
    // Перший файл
    using (FileStream source1 = File.Open("alice29.txt", FileMode.Open, FileAccess.Read))
    {
        // Другий файл
        using (FileStream source2 = File.Open("asyoulike.txt", FileMode.Open, FileAccess.Read))
        {
            using (var archive = new Archive())
            {
                // Додаємо файли до архіву
                archive.CreateEntry("alice29.txt", source1);
                archive.CreateEntry("asyoulik3.txt", source2);
                // Стискаємо файли
                archive.Save(zipFile, new ArchiveSaveOptions() { Encoding = Encoding.ASCII, ArchiveComment = "two files are compressed in this archive" });
            }
        }
    }
}

Стиснення файлів за допомогою класу FileInfo

Файли можна завантажити також через клас FileInfo і потім додати до архіву так само, як і раніше. Клас FileInfo надає властивості та методи для створення, копіювання, видалення, переміщення та відкриття файлів, а також полегшує створення об’єктів FileStream.

using (FileStream zipFile = File.Open("compressed_files.zip", FileMode.Create))
{
    // Файли, які додаються до архіву
    FileInfo fi1 = new FileInfo("alice29.txt");
    FileInfo fi2 = new FileInfo("fields.c");
    using (var archive = new Archive())
    {
        archive.CreateEntry("alice29.txt", fi1);
        archive.CreateEntry("fields.c", fi2);
        archive.Save(zipFile, new ArchiveSaveOptions() { Encoding = Encoding.ASCII });
    }
}

Збереження файлів у архіві без стискання

// Створює ZIP‑архів без стискання файлів
using (FileStream zipFile = File.Open(dataDir + "StoreMultipleFilesWithoutCompression_out.zip", FileMode.Create))
{
    FileInfo fi1 = new FileInfo(dataDir + "alice29.txt");
    FileInfo fi2 = new FileInfo(dataDir + "lcet10.txt");

    using (Archive archive = new Archive(new ArchiveEntrySettings(new StoreCompressionSettings())))
    {
        archive.CreateEntry("alice29.txt", fi1);
        archive.CreateEntry("lcet10.txt", fi2);
        archive.Save(zipFile, new ArchiveSaveOptions() { Encoding = Encoding.ASCII });
    }
}

Як створити ZIP‑архів з паролем у C#

using (var archive = new Archive(new ArchiveEntrySettings(encryptionSettings: new TraditionalEncryptionSettings("pass"))))
{
    archive.CreateEntry("entry_name1.dat", "input_file1.dat");
    archive.CreateEntry("entry_name2.dat", "input_file2.dat");
    archive.Save("result_archive.zip");
}

Параметр encryptionSettings використовується для створення архіву, захищеного паролем.

Як розпакувати ZIP‑архів з паролем у C#

using (var archive = new Archive("input_archive.zip", new ArchiveLoadOptions{DecryptionPassword = "pass"}))
{
    archive.ExtractToDirectory("\\outputDirectory");
}

Параметр DecryptionPassword у ArchiveLoadOptions дозволяє відкрити захищений паролем архів.

Для повних прикладів і тестових файлів відвідайте репозиторій: https://github.com/aspose-zip/Aspose.ZIP-for-.NET .

Використання LZMA‑стиснення у ZIP‑архіві

Алгоритм Лемпеля‑Зіва‑Маркова (LZMA) забезпечує безвтратне стиснення даних. LZMA‑стиснення в ZIP‑архіві дозволяє зберігати LZMA‑стиснені записи. Нижче наведено приклад реалізації LZMA‑стиснення за допомогою Aspose.ZIP API .

using (FileStream zipFile = File.Open(dataDir + "LZMACompression_out.zip", FileMode.Create))
{
    using (Archive archive = new Archive(new ArchiveEntrySettings(new LzmaCompressionSettings())))
    {
        archive.CreateEntry("sample.txt", dataDir + "sample.txt");
        archive.Save(zipFile);
    }
}

Використання BZip2‑стиснення у ZIP‑архіві

BZip2 – це вільна програма для стиснення файлів, що базується на алгоритмі Бурроуза‑Уілера. Вона стискає лише окремі файли і не є архіватором. Розроблена Джуліаном Сьюардом, підтримується Марком Вілярдом та Мікаєм Снайдером. Приклад використання BZip2‑стиснення через Aspose.ZIP API .

using (FileStream zipFile = File.Open(dataDir + "Bzip2Compression_out.zip", FileMode.Create))
{
    using (Archive archive = new Archive(new ArchiveEntrySettings(new Bzip2CompressionSettings())))
    {
        archive.CreateEntry("sample.txt", dataDir + "sample.txt");
        archive.Save(zipFile);
    }
}

Використання PPMd‑стиснення у ZIP‑архіві

PPM (Prediction by Partial Matching) – адаптивна статистична технологія стиснення, що базується на контекстному моделюванні. Алгоритм PPMd використовується для передбачення наступних символів у потоці даних. Приклад реалізації PPMd‑стиснення за допомогою Aspose.ZIP API .

using (FileStream zipFile = File.Open(dataDir + "PPMdCompression_out.zip", FileMode.Create))
{
    using (Archive archive = new Archive(new ArchiveEntrySettings(new PPMdCompressionSettings())))
    {
        archive.CreateEntry("sample.txt", dataDir + "sample.txt");
        archive.Save(zipFile);
    }
}

Декомпресія архіву з одним файлом

using (FileStream fs = File.OpenRead(dataDir + "CompressSingleFile_out.zip"))
{
    using (Archive archive = new Archive(fs))
    {
        int percentReady = 0;
        archive.Entries[0].ExtractionProgressed += (s, e) =>
        {
            int percent = (int)((100 * e.ProceededBytes) / ((ArchiveEntry)s).UncompressedSize);
            if (percent > percentReady)
            {
                Console.WriteLine(string.Format("{0}% decompressed", percent));
                percentReady = percent;
            }
        };
        archive.Entries[0].Extract(dataDir + "alice_extracted_out.txt");
    }
}

Декомпресія архіву з кількома файлами

using (FileStream zipFile = File.Open(dataDir + "CompressMultipleFiles_out.zip", FileMode.Open))
{
    StringBuilder sb = new StringBuilder("Entries are: ");
    int percentReady = 0;
    using (Archive archive = new Archive(zipFile,
        new ArchiveLoadOptions()
        {
            EntryListed = (s, e) => { sb.AppendFormat("{0}, ", e.Entry.Name); },
            EntryExtractionProgressed = (s, e) =>
            {
                int percent = (int)((100 * e.ProceededBytes) / ((ArchiveEntry)s).UncompressedSize);
                if (percent > percentReady)
                {
                    Console.WriteLine(string.Format("{0}% compressed", percent)); percentReady = percent;
                }
            }
        }))
    {
        Console.WriteLine(sb.ToString(0, sb.Length - 2));
        using (var extracted = File.Create(dataDir + "alice_extracted_out.txt"))
        {
            using (var decompressed = archive.Entries[0].Open())
            {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while (0 < (bytesRead = decompressed.Read(buffer, 0, buffer.Length)))
                {
                    extracted.Write(buffer, 0, bytesRead);
                }
                // Читаємо з розпакованого потоку у файл.
            }
        }
        percentReady = 0;
        archive.Entries[1].Extract(dataDir + "asyoulik_extracted_out.txt");
    }
}

Витягування архіву без стискання

using (FileStream zipFile = File.Open(dataDir + "StoreMultipleFilesWithoutCompression_out.zip", FileMode.Open))
{
    using (Archive archive = new Archive(zipFile))
    {
        using (var extracted = File.Create(dataDir + "alice_extracted_store_out.txt"))
        {
            using (var decompressed = archive.Entries[0].Open())
            {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while (0 < (bytesRead = decompressed.Read(buffer, 0, buffer.Length)))
                {
                    extracted.Write(buffer, 0, bytesRead);
                }
                // Читаємо з розпакованого потоку у файл.
            }
        }

        using (var extracted = File.Create(dataDir + "asyoulik_extracted_store_out.txt"))
        {
            using (var decompressed = archive.Entries[1].Open())
            {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while (0 < (bytesRead = decompressed.Read(buffer, 0, buffer.Length)))
                {
                    extracted.Write(buffer, 0, bytesRead);
                }
                // Читаємо з розпакованого потоку у файл.
            }
        }
    }
}

Для повних прикладів і тестових файлів відвідайте репозиторій: https://github.com/aspose-zip/Aspose.ZIP-for-.NET .