openplanning

Nén và giải nén trong C#

  1. Sơ đồ phân cấp các lớp
  2. ZipFile
  3. ZipArchive
  4. Phụ lục: Khắc phục lỗi

1. Sơ đồ phân cấp các lớp

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ích dữ liệu và mở file dữ liệu zip.
ZipArchive
Đại diện cho tập các file được nén trong một file có định dạng ZIP.
ZipArchiveEntry
Đại diện cho một tập tin nằm trong file đị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.

2. 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ẽ được nén.
            string inputDir = "C:/test/inputdir";

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

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

            // Tạo ra file zip bằng cách nén một 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

3. 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ể tạo được đố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ụ:
Entry:
  Name = data.docx
  FullName = data.docx
Entry:
  Name = image.bmp
  FullName = image.bmp
Entry:
  Name = readme.txt
  FullName = readme.txt
Entry:
  Name = Dotnet.docx
  FullName = documents\Dotnet.docx
Entry:
  Name = java.docx
  FullName = documents\java.docx
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 đầu ra để giải nén ra.
            string extractPath = "c:/test/extract";

            // 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);

                        // 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 này tồn tại.
                        // Ví dụ: C:/test/extract/documents
                        fileInfo.Directory.Create();

                        // Ghi đè (overwrite) file cũ nếu nó đã tồn tại.
                        entry.ExtractToFile(entryOuputPath,true);
                    }
                }
            } 
            Console.ReadLine();
        }
    } 
}
Chạy ví dụ:
Found: data.docx
 - Extract entry: data.docx
 - Entry Output Path: c:/test/extract\data.docx
Found: image.bmp
Found: readme.txt
Found: documents\Dotnet.docx
 - Extract entry: documents\Dotnet.docx
 - Entry Output Path: c:/test/extract\documents\Dotnet.docx
Found: documents\java.docx
 - Extract entry: documents\java.docx
 - Entry Output Path: c:/test/extract\documents\java.docx
Bạn cũng có thể trèn 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 Stream để đọ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 Stream để 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ả.

4. Phụ lục: Khắc phục lỗi

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: