Procedure: Bestanden comprimeren en extraheren

De System.IO.Compression naamruimte bevat de volgende klassen voor het comprimeren en decomprimeren van bestanden en streams. U kunt deze typen ook gebruiken om de inhoud van een gecomprimeerd bestand te lezen en te wijzigen:

In de volgende voorbeelden ziet u enkele bewerkingen die u kunt uitvoeren met gecomprimeerde bestanden. Voor deze voorbeelden moeten de volgende NuGet-pakketten worden toegevoegd aan uw project:

Als u .NET Framework gebruikt, voegt u verwijzingen naar deze twee bibliotheken toe aan uw project:

  • System.IO.Compression
  • System.IO.Compression.FileSystem

Voorbeeld 1: Een .zip-bestand maken en extraheren

In het volgende voorbeeld ziet u hoe u een gecomprimeerd .zip-bestand maakt en extraheert met behulp van de ZipFile klasse. Het voorbeeld comprimeert de inhoud van een map in een nieuw .zip bestand en extraheert het bestand vervolgens naar een nieuwe map.

Als u het voorbeeld wilt uitvoeren, maakt u een startmap in uw programmamap en vult u deze in met bestanden die u wilt zippen.

using System;
using System.IO.Compression;

class Program
{
    static void Main(string[] args)
    {
        string startPath = @".\start";
        string zipPath = @".\result.zip";
        string extractPath = @".\extract";

        ZipFile.CreateFromDirectory(startPath, zipPath);

        ZipFile.ExtractToDirectory(zipPath, extractPath);
    }
}
Imports System.IO.Compression

Module Module1

    Sub Main()
        Dim startPath As String = ".\start"
        Dim zipPath As String = ".\result.zip"
        Dim extractPath As String = ".\extract"

        ZipFile.CreateFromDirectory(startPath, zipPath)

        ZipFile.ExtractToDirectory(zipPath, extractPath)
    End Sub

End Module

Voorbeeld 2: Specifieke bestandsextensies extraheren

In het volgende voorbeeld wordt de inhoud van een bestaand .zip bestand herhaald en worden bestanden geëxtraheerd met een .txt-extensie . De klasse gebruikt de ZipArchive klasse voor toegang tot het .zip-bestand en de ZipArchiveEntry klasse om de afzonderlijke vermeldingen te inspecteren. De extensiemethode ExtractToFile voor het ZipArchiveEntry object is beschikbaar in de System.IO.Compression.ZipFileExtensions klasse.

Als u het voorbeeld wilt uitvoeren, plaatst u een .zip bestand met de naam result.zip in uw programmamap. Geef desgevraagd een mapnaam op waarnaar u wilt extraheren.

Belangrijk

Wanneer u bestanden uitpakt, moet u zoeken naar schadelijke bestandspaden, die kunnen ontsnappen uit de map waarin u uitpakt. Dit wordt een padkruisingsaanval genoemd. In het volgende voorbeeld ziet u hoe u kunt controleren op schadelijke bestandspaden en hoe u het bestand kunt uitpakken.

using System;
using System.IO;
using System.IO.Compression;

class Program
{
    static void Main(string[] args)
    {
        string zipPath = @".\result.zip";

        Console.WriteLine("Provide path where to extract the zip file:");
        string extractPath = Console.ReadLine();

        // Normalizes the path.
        extractPath = Path.GetFullPath(extractPath);

        // Ensures that the last character on the extraction path
        // is the directory separator char.
        // Without this, a malicious zip file could try to traverse outside of the expected
        // extraction path.
        if (!extractPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
            extractPath += Path.DirectorySeparatorChar;

        using (ZipArchive archive = ZipFile.OpenRead(zipPath))
        {
            foreach (ZipArchiveEntry entry in archive.Entries)
            {
                if (entry.FullName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
                {
                    // Gets the full path to ensure that relative segments are removed.
                    string destinationPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName));

                    // Ordinal match is safest, case-sensitive volumes can be mounted within volumes that
                    // are case-insensitive.
                    if (destinationPath.StartsWith(extractPath, StringComparison.Ordinal))
                        entry.ExtractToFile(destinationPath);
                }
            }
        }
    }
}
Imports System.IO
Imports System.IO.Compression

Module Module1

    Sub Main()
        Dim zipPath As String = ".\result.zip"

        Console.WriteLine("Provide path where to extract the zip file:")
        Dim extractPath As String = Console.ReadLine()

        ' Normalizes the path.
        extractPath = Path.GetFullPath(extractPath)

        ' Ensures that the last character on the extraction path
        ' is the directory separator char. 
        ' Without this, a malicious zip file could try to traverse outside of the expected
        ' extraction path.
        If Not extractPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) Then
            extractPath += Path.DirectorySeparatorChar
        End If

        Using archive As ZipArchive = ZipFile.OpenRead(zipPath)
            For Each entry As ZipArchiveEntry In archive.Entries
                If entry.FullName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase) Then

                    ' Gets the full path to ensure that relative segments are removed.
                    Dim destinationPath As String = Path.GetFullPath(Path.Combine(extractPath, entry.FullName))

                    ' Ordinal match is safest, case-sensitive volumes can be mounted within volumes that
                    ' are case-insensitive.
                    If destinationPath.StartsWith(extractPath, StringComparison.Ordinal) Then
                        entry.ExtractToFile(destinationPath)
                    End If

                End If
            Next
        End Using
    End Sub

End Module

Voorbeeld 3: Een bestand toevoegen aan een bestaand .zip-bestand

In het volgende voorbeeld wordt de ZipArchive klasse gebruikt voor toegang tot een bestaand .zip-bestand en wordt er een bestand aan toegevoegd. Het nieuwe bestand wordt gecomprimeerd wanneer u het toevoegt aan het bestaande .zip-bestand .

using System;
using System.IO;
using System.IO.Compression;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            using (FileStream zipToOpen = new FileStream(@"c:\users\exampleuser\release.zip", FileMode.Open))
            {
                using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
                {
                    ZipArchiveEntry readmeEntry = archive.CreateEntry("Readme.txt");
                    using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
                    {
                            writer.WriteLine("Information about this package.");
                            writer.WriteLine("========================");
                    }
                }
            }
        }
    }
}
Imports System.IO
Imports System.IO.Compression

Module Module1

    Sub Main()
        Using zipToOpen As FileStream = New FileStream("c:\users\exampleuser\release.zip", FileMode.Open)
            Using archive As ZipArchive = New ZipArchive(zipToOpen, ZipArchiveMode.Update)
                Dim readmeEntry As ZipArchiveEntry = archive.CreateEntry("Readme.txt")
                Using writer As StreamWriter = New StreamWriter(readmeEntry.Open())
                    writer.WriteLine("Information about this package.")
                    writer.WriteLine("========================")
                End Using
            End Using
        End Using
    End Sub

End Module

Voorbeeld 4: bestanden comprimeren en decomprimeren .gz

U kunt de GZipStream en DeflateStream klassen ook gebruiken om gegevens te comprimeren en decomprimeren. Ze gebruiken hetzelfde compressie-algoritme. U kunt objecten die zijn geschreven naar een .gz-bestand decomprimeren GZipStream met behulp van veel veelgebruikte hulpprogramma's. In het volgende voorbeeld ziet u hoe u een map met bestanden comprimeert en decomprimeert met behulp van de GZipStream klasse:

using System;
using System.IO;
using System.IO.Compression;

public class Program
{
    private static string directoryPath = @".\temp";
    public static void Main()
    {
        DirectoryInfo directorySelected = new DirectoryInfo(directoryPath);
        Compress(directorySelected);

        foreach (FileInfo fileToDecompress in directorySelected.GetFiles("*.gz"))
        {
            Decompress(fileToDecompress);
        }
    }

    public static void Compress(DirectoryInfo directorySelected)
    {
        foreach (FileInfo fileToCompress in directorySelected.GetFiles())
        {
            using (FileStream originalFileStream = fileToCompress.OpenRead())
            {
                if ((File.GetAttributes(fileToCompress.FullName) &
                   FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz")
                {
                    using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz"))
                    {
                        using (GZipStream compressionStream = new GZipStream(compressedFileStream,
                           CompressionMode.Compress))
                        {
                            originalFileStream.CopyTo(compressionStream);
                        }
                    }
                    FileInfo info = new FileInfo(directoryPath + Path.DirectorySeparatorChar + fileToCompress.Name + ".gz");
                    Console.WriteLine($"Compressed {fileToCompress.Name} from {fileToCompress.Length.ToString()} to {info.Length.ToString()} bytes.");
                }
            }
        }
    }

    public static void Decompress(FileInfo fileToDecompress)
    {
        using (FileStream originalFileStream = fileToDecompress.OpenRead())
        {
            string currentFileName = fileToDecompress.FullName;
            string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);

            using (FileStream decompressedFileStream = File.Create(newFileName))
            {
                using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
                {
                    decompressionStream.CopyTo(decompressedFileStream);
                    Console.WriteLine($"Decompressed: {fileToDecompress.Name}");
                }
            }
        }
    }
}
Imports System.IO
Imports System.IO.Compression

Module Module1

    Private directoryPath As String = ".\temp"
    Public Sub Main()
        Dim directorySelected As New DirectoryInfo(directoryPath)
        Compress(directorySelected)

        For Each fileToDecompress As FileInfo In directorySelected.GetFiles("*.gz")
            Decompress(fileToDecompress)
        Next
    End Sub

    Public Sub Compress(directorySelected As DirectoryInfo)
        For Each fileToCompress As FileInfo In directorySelected.GetFiles()
            Using originalFileStream As FileStream = fileToCompress.OpenRead()
                If (File.GetAttributes(fileToCompress.FullName) And FileAttributes.Hidden) <> FileAttributes.Hidden And fileToCompress.Extension <> ".gz" Then
                    Using compressedFileStream As FileStream = File.Create(fileToCompress.FullName & ".gz")
                        Using compressionStream As New GZipStream(compressedFileStream, CompressionMode.Compress)

                            originalFileStream.CopyTo(compressionStream)
                        End Using
                    End Using
                    Dim info As New FileInfo(directoryPath & Path.DirectorySeparatorChar & fileToCompress.Name & ".gz")
                    Console.WriteLine($"Compressed {fileToCompress.Name} from {fileToCompress.Length.ToString()} to {info.Length.ToString()} bytes.")

                End If
            End Using
        Next
    End Sub


    Private Sub Decompress(ByVal fileToDecompress As FileInfo)
        Using originalFileStream As FileStream = fileToDecompress.OpenRead()
            Dim currentFileName As String = fileToDecompress.FullName
            Dim newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length)

            Using decompressedFileStream As FileStream = File.Create(newFileName)
                Using decompressionStream As GZipStream = New GZipStream(originalFileStream, CompressionMode.Decompress)
                    decompressionStream.CopyTo(decompressedFileStream)
                    Console.WriteLine($"Decompressed: {fileToDecompress.Name}")
                End Using
            End Using
        End Using
    End Sub
End Module

Zie ook