Nén và giải nén trong C#
Công ty Vĩnh Cửu tuyển dụng lập trình viên Java

1- Giới thiệu

History:
  • Create document: 04-12-2015

2- Sơ đồ thừa kế các class nén và giải nén

Dưới đây là danh mục các class sử dụng cho mục đích nén và giải nén file. Chúng nằm trong namespace System.IO.Compression.
Class Mô tả
ZipFile Cung cấp các phương thức tĩnh cho việc tạo, trính dữ liệu và mở file dữ liệu zip.
ZipArchive Đại diện cho gói các file được nén trong định dạng ZIP.
ZipArchiveEntry Đại diện cho một tập tin nằm trong file nén định dạng ZIP.
DeflateStream Cung cấp các phương thức và thuộc tính cho các luồng (stream) nén và giải nén bằng cách sử dụng thuật toán Deflate.
GZipStream Cung cấp các phương thức và thuộc tính được sử dụng để nén và giải nén các luồng (stream).

Chú ý rằng các class này được đưa vào C# từ phiên bản 4.5, vì vậy project của bạn phải sử dụng .NET phiên bản 4.5 hoặc mới hơn.

3- ZipFile

Class ZipFile là một class tiện ích, nó có nhiều phương thức tĩnh giúp bạn mở file zip, trích lấy dữ liệu, hoặc các tình huống hay được sử dụng như  nén một thư mục thành một file zip, giải nén file zip ra một thư mục, ..
Ví dụ đơn giản dưới đây sử dụng các phương thức tiện ích của class ZipFile nén một thư mục thành một file zip và sau đó giải nén file này sang một thư mục khác.
ZipDirectoryDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Compression;

namespace CompressionTutorial
{
  class ZipDirectoryDemo
  {
      public static void Main(string[] args)
      {

          // Thư mục sẽ nén
          string inputDir = "C:/test/inputdir";

          // File đầu ra khi nén thư mục trên.
          string zipPath = "C:/test/data.zip";

          // Giải nén file zip ra thư mục.
          string extractPath = "C:/test/outputdir";

          // Tạo ra file zip bằng cách nén cả thư mục.
          ZipFile.CreateFromDirectory(inputDir, zipPath);

          // Giải nén file zip ra một thư mục.
          ZipFile.ExtractToDirectory(zipPath, extractPath);

          Console.WriteLine("Done!");
      }
  }

}
Nếu bạn nhận được một thông báo lỗi: "The name 'ZipFile' does not exist in the current context" (Mặc dù đã khai báo using System.IO.Compression) điều đó có nghĩa là project của bạn sử dụng .NET cũ hơn 4.5 hoặc chương trình không tìm thấy thư viện DLL. Bạn có thể xem cách fix lỗi này trong phụ lục ở cuối của tài liệu này.
Chạy ví dụ và nhận được kết quả:
  • data.zip

4- ZipArchive

ZipArchive đại diện cho một bó các file đã nén trong một file định dạng ZIP.  Bạn có thể lấy ra đối tượng ZipArchive thông qua phương thức OpenRead của class ZipFile. Thông qua ZipArchive bạn có thể đọc các file con đã được nén trong file zip.
Ví dụ dưới đây liệt kê ra các ZipArchiveEntry có trong file zip.
ListArchiveEntryDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Compression;
using System.IO;

namespace CompressionTutorial
{
  class ListArchiveEntryDemo
  {

      public static void Main(string[] args)
      {
          string zipPath =  "c:/test/data.zip";

          using (ZipArchive archive = ZipFile.OpenRead(zipPath))
          {
              // Duyệt danh sách các ZipArchiveEntry.
              foreach (ZipArchiveEntry entry in archive.Entries)
              {
                  Console.WriteLine("Entry:");
                  Console.WriteLine("  Name = " + entry.Name);
                  Console.WriteLine("  FullName = " + entry.FullName);
              }
          }

          Console.Read();
      }
  }

}
Chạy ví dụ:
Trích các file dữ liệu trong file zip:
ExtractDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Compression;
using System.IO;

namespace CompressionTutorial
{
  class ExtractDemo {
      static void Main(string[] args)
      {
          string zipPath = "c:/test/data.zip";
          // Thư mục giải nén ra.
          string extractPath = "c:/test/extract";

          // if it doesn't exist, create
          // Nếu thư mục không tồn tại, tạo nó.
          if (!Directory.Exists(extractPath))
          {
              System.IO.Directory.CreateDirectory(extractPath);
          }

          using (ZipArchive archive = ZipFile.OpenRead(zipPath))
          {
              foreach (ZipArchiveEntry entry in archive.Entries)
              {
                  Console.WriteLine("Found: " + entry.FullName);

                  // Tìm kiếm các Entry có đuôi .docx
                  if (entry.FullName.EndsWith(".docx", StringComparison.OrdinalIgnoreCase))
                  {
                      // Ví dụ: documents/Dotnet.docx
                      Console.WriteLine(" - Extract entry: " + entry.FullName);

                      // Ví dụ: C:/test/extract/documents/Dotnet.docx
                      string entryOuputPath = Path.Combine(extractPath, entry.FullName);

                      Console.WriteLine(" - Entry Ouput Path: " + entryOuputPath);

                      FileInfo fileInfo = new FileInfo(entryOuputPath);

                      // Đảm bảo rằng thưc mục chứa file tồn tại.
                      // Ví dụ: C:/test/extract/documents
                      fileInfo.Directory.Create();

                      // Ghi đè file cũ nếu nó đã tồn tại.
                      entry.ExtractToFile(entryOuputPath,true);
                  }
              }
          }

          Console.ReadLine();
      }
  }

}
Chạy ví dụ:
Bạn cũng có thể ghi thêm các file vào trong một file zip có sẵn.
AddEntryDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Compression;
using System.IO;

namespace CompressionTutorial
{
   class AddEntryDemo
   {
       static void Main(string[] args)
       {
           string zipPath = "C:/test/data.zip";

           // Mở một luồng đọc file zip.
           using (FileStream zipStream = new FileStream(zipPath, FileMode.Open))
           {
               // Tạo đối tượng ZipArchive.
               using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Update))
               {
                   // Thêm một entry vào ZipArchive.
                   ZipArchiveEntry readmeEntry = archive.CreateEntry("note/Note.txt");

                   // Tạo một luồng ghi nội dung vào entry.
                   using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
                   {
                       writer.WriteLine("## Note.txt");
                       writer.WriteLine("========================");
                   }
               }
           }
       }
   }

}
Chạy ví dụ và nhận được kết quả.

5- TODO

  • TODO 50%

6- Phụ lục: Fix lỗi The name 'xxx' does not exist in the current context

Khi bạn nhận được lỗi: "The name 'ZipFile' does not exist in the current context" (Mặc dù đã khai báo using System.IO.Compression) điều đó có nghĩa là bạn đã sử dụng .NET cũ hơn phiên bản 4.5 hoặc chương trình không tìm được thư viện DLL cần thiết.
Nhấn phải chuột vào Project chọn Properties, đảm bảo rằng project của bạn đã sử dụng .NET Framework 4.5 trở lên.
Chạy lại class của bạn xem trình biên dịch còn thông báo lỗi đó nữa hay không. Trong trường hợp vẫn thông báo lỗi bạn cần chỉ định rõ vị trí thư viện DLL.
  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.IO.Compression.FileSystem.dll
  • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.IO.Compression.FileSystem.dll
Nhấn phải chuột vào Project chọn:
  • Add/Reference..
Chọn file: System.IO.Compression.FileSystem.dll
Tương tự nếu bạn nhận được thông báo "The name 'ZipArchive' does not exist in the current context" (Mặc dù đã khai báo using System.IO.Compression) bạn cần khai báo sử dụng thư viện System.IO.Compression.dll:
Tương tự nếu bạn nhận được thông báo "The name 'Path' does not exist in the current context" (Mặc dù đã khai báo using System.IO) bạn cần khai báo sử dụng thư viện mscorlib.dll: