Procédure : compresser et extraire des fichiersHow to: Compress and extract files

L'espace de noms System.IO.Compression contient les types suivants pour la compression et la décompression de fichiers et de flux.The System.IO.Compression namespace contains the following types for compressing and decompressing files and streams. Vous pouvez également utiliser ces types pour lire et modifier le contenu d’un fichier compressé.You can also use these types to read and modify the contents of a compressed file.

Les exemples suivants présentent certaines des opérations que vous pouvez effectuer avec des fichiers compressés.The following examples show some of the operations you can perform with compressed files.

Exemple 1 : Créer et extraire un fichier .zipExample 1: Create and extract a .zip file

L’exemple suivant montre comment créer et extraire un fichier .zip à l’aide de la classe ZipFile.The following example shows how to create and extract a compressed .zip file by using the ZipFile class. Cet exemple compresse le contenu d’un dossier dans un nouveau fichier .zip, puis extrait ce fichier zip dans un nouveau dossier.The example compresses the contents of a folder into a new .zip file, and then extracts the zip to a new folder.

Pour exécuter l’exemple, créez un dossier start dans le dossier de votre programme, puis placez-y les fichiers à compresser.To run the sample, create a start folder in your program folder and populate it with files to zip.

Si vous obtenez l’erreur de build indiquant que le nom « FichierZip» n’existe pas dans le contexte actuel, ajoutez une référence à l’assembly System.IO.Compression.FileSystem à votre projet.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

Exemple 2 : Extraire des extensions de fichier spécifiquesExample 2: Extract specific file extensions

L’exemple suivant montre comment parcourir le contenu d’un fichier .zip existant et en extraire les fichiers ayant une extension .txt.The next example iterates through the contents of an existing .zip file and extracts files that have a .txt extension. Il utilise la classe ZipArchive pour accéder au fichier zip, et la classe ZipArchiveEntry pour inspecter chaque entrée.It uses the ZipArchive class to access the zip, and the ZipArchiveEntry class to inspect the individual entries. La méthode d’extension ExtractToFile de l’objet ZipArchiveEntry est disponible dans la classe System.IO.Compression.ZipFileExtensions.The extension method ExtractToFile for the ZipArchiveEntry object is available in the System.IO.Compression.ZipFileExtensions class.

Pour exécuter l’exemple, placez un fichier .zip appelé result.zip dans le dossier de votre programme.To run the sample, place a .zip file called result.zip in your program folder. Lorsque vous y êtes invité, fournissez le nom du dossier vers lequel extraire les fichiers.When prompted, provide a folder name to extract to.

Si vous obtenez l’erreur de build indiquant que le nom « FichierZip» n’existe pas dans le contexte actuel, ajoutez une référence à l’assembly System.IO.Compression.FileSystem à votre projet.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.

Si vous obtenez l’erreur indiquant que le type 'ArchiveZip' est défini dans un assembly qui n’est pas référencé, ajoutez une référence à l’assembly System.IO.Compression de votre projet.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.

Important

Lors de la décompression des fichiers, vous devez rechercher les chemins malveillants qui risquent d’extraire les fichiers en dehors du répertoire.When unzipping files, you must look for malicious file paths, which can escape out of the directory you unzip into. Il s’agit d’une attaque par chemin transversal.This is known as a path traversal attack. L’exemple suivant montre comment rechercher les chemins malveillants et garantir une décompression sûre.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

Exemple 3 : Ajouter un fichier à un zip existantExample 3: Add a file to an existing zip

L’exemple suivant utilise la classe ZipArchive pour accéder à un fichier .zip existant, et y ajouter un fichier.The following example uses the ZipArchive class to access an existing .zip file, and adds a file to it. Le nouveau fichier est compressé quand vous l’ajoutez au fichier zip existant.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

Exemple 4 : Compresser et décompresser les fichiers .gzExample 4: Compress and decompress .gz files

Vous pouvez également utiliser les classes GZipStream et DeflateStream pour compresser et décompresser des données.You can also use the GZipStream and DeflateStream classes to compress and decompress data. Elles utilisent le même algorithme de compression.They use the same compression algorithm. Vous pouvez décompresser les objets GZipStream qui sont écrits dans un fichier .gz à l’aide de nombreux outils courants.You can decompress GZipStream objects that are written to a .gz file by using many common tools. L’exemple suivant montre comment compresser et décompresser un répertoire de fichiers à l’aide de la classe GZipStream :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

Voir aussiSee also