Vorgehensweise: Komprimieren und Extrahieren von DateienHow to: Compress and extract files

Der System.IO.Compression-Namespace enthält die folgenden Typen zum Komprimieren und Dekomprimieren von Dateien und Streams.The System.IO.Compression namespace contains the following types for compressing and decompressing files and streams. Sie können diese Typen auch verwenden, um den Inhalt einer komprimierten Datei zu lesen und zu ändern.You can also use these types to read and modify the contents of a compressed file.

Anhand der folgenden Beispiele werden einige der Vorgänge erläutert, die Sie mit komprimierten Dateien ausführen können.The following examples show some of the operations you can perform with compressed files.

Beispiel 1: Erstellen und Extrahieren einer ZIP-DateiExample 1: Create and extract a .zip file

Das folgende Beispiel zeigt, wie Sie mithilfe der ZipFile-Klasse eine komprimierte ZIP-Datei erstellen und extrahieren können.The following example shows how to create and extract a compressed .zip file by using the ZipFile class. In dem Beispiel wird der Inhalt eines Ordners in eine neue ZIP-Datei komprimiert, die anschließend in einen neuen Ordner extrahiert wird.The example compresses the contents of a folder into a new .zip file, and then extracts the zip to a new folder.

Wenn Sie das Beispiel ausführen möchten, erstellen Sie in Ihrem Programmordner einen Ordner für den Start, und füllen Sie diesen mit Dateien auf, die gezippt werden sollen.To run the sample, create a start folder in your program folder and populate it with files to zip.

Wenn der Buildfehler "The name 'ZipFile' does not exist in the current context." (Der Name „ZipFile“ ist im aktuellen Kontext nicht vorhanden.) zurückgegeben wird, fügen Sie dem Projekt einen Verweis auf die System.IO.Compression.FileSystem-Assembly hinzu.If you get the build error "The name 'ZipFile' does not exist in the current context," add a reference to the System.IO.Compression.FileSystem assembly to your project.

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

Beispiel 2: Extrahieren bestimmter DateierweiterungenExample 2: Extract specific file extensions

Im nächsten Beispiel wird der Inhalt einer vorhandenen ZIP-Datei durchlaufen, und Dateien mit der Erweiterung .txt werden extrahiert.The next example iterates through the contents of an existing .zip file and extracts files that have a .txt extension. Dabei wird die Klasse ZipArchive verwendet, um auf die Zip-Datei zuzugreifen, und mithilfe der Klasse ZipArchiveEntry werden die einzelnen Einträge untersucht.It uses the ZipArchive class to access the zip, and the ZipArchiveEntry class to inspect the individual entries. Die Erweiterungsmethode ExtractToFile für das ZipArchiveEntry-Objekt ist in der Klasse System.IO.Compression.ZipFileExtensions verfügbar.The extension method ExtractToFile for the ZipArchiveEntry object is available in the System.IO.Compression.ZipFileExtensions class.

Wenn Sie das Beispiel ausführen möchten, platzieren Sie die ZIP-Datei mit dem Namen result.zip in Ihrem Programmordner.To run the sample, place a .zip file called result.zip in your program folder. Geben Sie einen Ordnernamen an, in den die Datei extrahiert werden soll, wenn Sie dazu aufgefordert werden.When prompted, provide a folder name to extract to.

Wenn der Buildfehler "The name 'ZipFile' does not exist in the current context." (Der Name „ZipFile“ ist im aktuellen Kontext nicht vorhanden.) zurückgegeben wird, fügen Sie dem Projekt einen Verweis auf die System.IO.Compression.FileSystem-Assembly hinzu.If you get the build error "The name 'ZipFile' does not exist in the current context," add a reference to the System.IO.Compression.FileSystem assembly to your project.

Wenn der Fehler "The type 'ZipArchive' is defined in an assembly that is not referenced." (Der Typ „ZipArchive“ ist in einer Assembly definiert, auf die nicht verwiesen wird.) zurückgegeben wird, fügen Sie dem Projekt einen Verweis auf die System.IO.Compression-Assembly hinzu.If you get the error "The type 'ZipArchive' is defined in an assembly that is not referenced," add a reference to the System.IO.Compression assembly to your project.

Wichtig

Beim Entzippen von Dateien müssen Sie auf schädliche Dateipfade achten, die aus dem Verzeichnis weisen können, in das Sie extrahieren möchten.When unzipping files, you must look for malicious file paths, which can escape out of the directory you unzip into. Dies wird als Path Traversal-Angriff bezeichnet.This is known as a path traversal attack. Im folgenden Beispiel wird gezeigt, wie Sie eine Überprüfung auf schädliche Dateipfade durchführen und Dateien sicher entzippen können.The following example demonstrates how to check for malicious file paths and provides a safe way to unzip.

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

Beispiel 3: Hinzufügen einer Datei zu einer bestehenden ZIP-DateiExample 3: Add a file to an existing zip

Im folgenden Beispiel wird die Klasse ZipArchive verwendet, um auf eine vorhandene ZIP-Datei zuzugreifen, der anschließend eine Datei hinzugefügt wird.The following example uses the ZipArchive class to access an existing .zip file, and adds a file to it. Die neue Datei wird komprimiert, wenn Sie sie zur vorhandenen ZIP-Datei hinzufügen.The new file gets compressed when you add it to the existing zip.

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

Beispiel 4: Komprimieren und Dekomprimieren von GZ-DateienExample 4: Compress and decompress .gz files

Sie können auch die Klassen GZipStream und DeflateStream verwenden, um Daten zu komprimieren und zu dekomprimieren.You can also use the GZipStream and DeflateStream classes to compress and decompress data. Der Komprimierungsalgorithmus ist der gleiche.They use the same compression algorithm. Es gibt viele beliebte Tools, die Sie verwenden können, um GZipStream-Objekte zu dekomprimieren, die in eine GZ-Datei geschrieben wurden.You can decompress GZipStream objects that are written to a .gz file by using many common tools. Das folgende Beispiel zeigt, wie Sie ein Dateiverzeichnis mithilfe der GZipStream-Klasse komprimieren und dekomprimieren:The following example shows how to compress and decompress a directory of files by using the GZipStream class:

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

Siehe auchSee also