База знаний

Сжатие и распаковка файлов с помощью C# — Сжатие и декомпрессия файлов

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

ZIP — это архивный формат, поддерживающий без потерь сжатие данных. ZIP‑файл может содержать один или несколько файлов или каталогов, которые были сжаты. Обычно ZIP‑файлы используют расширения .zip или .ZIP и MIME‑тип application/zip. Многие программы используют ZIP как базовый формат, часто под другим названием. При работе с файловой системой через пользовательский интерфейс значки ZIP‑файлов часто выглядят как документ или объект с изображением молнии‑молнии.

Существует много способов сжать (архивировать) файлы ; выбор зависит от используемой операционной системы. Почти каждый день нам приходится архивировать или разархивировать файлы и отправлять их на серверы хранения или платформы обмена. К счастью, этот процесс можно автоматизировать с помощью Aspose.ZIP 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 и затем добавить в ZIP‑архив тем же способом, что и ранее. Класс 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);
        // Создаём ZIP‑архив
        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‑архива, защищённого паролем.

Как разархивировать ZIP‑файл с паролем в C#

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

Класс ArchiveLoadOptions с установленным свойством DecryptionPassword позволяет открыть архив, защищённый паролем.

Для полного набора примеров и файлов данных перейдите на https://github.com/aspose-zip/Aspose.ZIP-for-.NET .

Использование LZMA‑сжатия внутри ZIP‑архива

Алгоритм Лемпеля‑Зива‑Маркова (LZMA) — это метод без потерь, использующий словарное сжатие. LZMA‑сжатие внутри ZIP‑архива позволяет хранить в контейнере записи, сжатые этим алгоритмом. Ниже показан пример реализации 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) — адаптивный статистический метод сжатия, основанный на контекстном моделировании и предсказании. Алгоритмы PPM могут также использоваться для кластеризации данных. Ниже пример реализации 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 .