web-dev-qa-db-fra.com

Création de répertoires dans un fichier ZipArchive C # .Net 4.5

Un ZipArchive est une collection de ZipArchiveEntries, et ajouter/supprimer des "entrées" fonctionne bien ..__ Mais il semble qu'il n'y ait aucune notion de répertoires/"archives" imbriquées. En théorie, la classe est découplée d'un système de fichiers, en ce sens que vous pouvez créer l'archive complètement dans un flux de mémoire. Toutefois, si vous souhaitez ajouter une structure de répertoire dans l'archive, vous devez préfixer le nom de l'entrée avec un chemin. 

Question: Comment voudriez-vous étendre ZipArchive pour créer une meilleure interface pour la création et la gestion de répertoires?

Par exemple, la méthode actuelle pour ajouter un fichier à un répertoire consiste à créer l'entrée avec le chemin du répertoire:

var entry = _archive.CreateEntry("directory/entryname");

alors que quelque chose dans ce sens me semble plus gentil: 

var directory = _archive.CreateDirectoryEntry("directory");
var entry = _directory.CreateEntry("entryname");
24
Meirion Hughes

Vous pouvez utiliser quelque chose comme ceci, autrement dit, créer la structure de répertoires à la main:

using (var fs = new FileStream("1.Zip", FileMode.Create))
using (var Zip = new ZipArchive(fs, ZipArchiveMode.Create))
{
    Zip.CreateEntry("12/3/"); // just end with "/"
}
44
Aimeast

Si vous travaillez sur un projet pouvant utiliser .NET complet, vous pouvez essayer d'utiliser La méthode ZipFile.CreateFromDirectory, comme expliqué ici :

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

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            string startPath = @"c:\example\start";
            string zipPath = @"c:\example\result.Zip";
            string extractPath = @"c:\example\extract";

            ZipFile.CreateFromDirectory(startPath, zipPath, CompressionLevel.Fastest, true);

            ZipFile.ExtractToDirectory(zipPath, extractPath);
        }
    }
}

Bien sûr, cela ne fonctionnera que si vous créez de nouveaux fichiers Zip basés sur un répertoire donné.

Selon le commentaire, la solution précédente ne conserve pas la structure de répertoires. Si cela est nécessaire, le code suivant peut résoudre ce problème:

    var InputDirectory = @"c:\example\start";
    var OutputFilename = @"c:\example\result.Zip";
    using (Stream zipStream = new FileStream(Path.GetFullPath(OutputFilename), FileMode.Create, FileAccess.Write))
    using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
    {
        foreach(var filePath in System.IO.Directory.GetFiles(InputDirectory,"*.*",System.IO.SearchOption.AllDirectories))
        {
            var relativePath = filePath.Replace(InputDirectory,string.Empty);
            using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            using (Stream fileStreamInZip = archive.CreateEntry(relativePath).Open())
                fileStream.CopyTo(fileStreamInZip);
        }
    }
9
hmadrigal

Voici une solution possible: 

public static class ZipArchiveExtension
{
    public static ZipArchiveDirectory CreateDirectory(this ZipArchive @this, string directoryPath)
    {
        return new ZipArchiveDirectory(@this, directoryPath);
    }
}

public class ZipArchiveDirectory
{
    private readonly string _directory;
    private ZipArchive _archive;

    internal ZipArchiveDirectory(ZipArchive archive, string directory)
    {
        _archive = archive;
        _directory = directory;
    }

    public ZipArchive Archive { get{return _archive;}}

    public ZipArchiveEntry CreateEntry(string entry)
    {
        return _archive.CreateEntry(_directory + "/" + entry);
    }

    public ZipArchiveEntry CreateEntry(string entry, CompressionLevel compressionLevel)
    {
        return _archive.CreateEntry(_directory + "/" + entry, compressionLevel);
    }
}

et utilisé: 

var directory = _archive.CreateDirectory(context);
var entry = directory.CreateEntry(context);
var stream = entry.Open();

mais je peux prévoir des problèmes de nidification, peut-être. 

7
Meirion Hughes

Je sais que je suis en retard à la fête (7.25.2018),

Mais cela fonctionne parfaitement pour moi, même avec un répertoire récursif.

Fichier d'extension pour ZipArchive:

public static class ZipArchiveExtension {

    public static void CreateEntryFromAny(this ZipArchive archive, String sourceName, String entryName = "") {
        var fileName = Path.GetFileName(sourceName);
        if (File.GetAttributes(sourceName).HasFlag(FileAttributes.Directory)) {
            archive.CreateEntryFromDirectory(sourceName, Path.Combine(entryName, fileName));
        } else {
            archive.CreateEntryFromFile(sourceName, Path.Combine(entryName, fileName), CompressionLevel.Fastest);
        }
    }

    public static void CreateEntryFromDirectory(this ZipArchive archive, String sourceDirName, String entryName = "") {
        string[] files = Directory.GetFiles(sourceDirName).Concat(Directory.GetDirectories(sourceDirName)).ToArray();
        archive.CreateEntry(Path.Combine(entryName, Path.GetFileName(sourceDirName)));
        foreach (var file in files) {
            var fileName = Path.GetFileName(file);
            archive.CreateEntryFromAny(file, entryName);
        }
    }

}

Et puis vous pouvez tout emporter, que ce soit un fichier ou un répertoire:

using (var memoryStream = new MemoryStream()) {
    using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
        archive.CreateEntryFromAny(sourcePath);
    }
}
1
Val

Utilisez l'approche récursive de Zip Folders with Sub Folders.

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;

public static async Task<bool> ZipFileHelper(IFolder folderForZipping, IFolder folderForZipFile, string zipFileName)
{
    if (folderForZipping == null || folderForZipFile == null
        || string.IsNullOrEmpty(zipFileName))
    {
        throw new ArgumentException("Invalid argument...");
    }

    IFile zipFile = await folderForZipFile.CreateFileAsync(zipFileName, CreationCollisionOption.ReplaceExisting);

    // Create Zip archive to access compressed files in memory stream
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive Zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
        {
            await ZipSubFolders(folderForZipping, Zip, "");
        }

        zipStream.Position = 0;
        using (Stream s = await zipFile.OpenAsync(FileAccess.ReadAndWrite))
        {
            zipStream.CopyTo(s);
        }
    }
    return true;
}

//Create Zip file entry for folder and subfolders("sub/1.txt")
private static async Task ZipSubFolders(IFolder folder, ZipArchive Zip, string dir)
{
    if (folder == null || Zip == null)
        return;

    var files = await folder.GetFilesAsync();
    var en = files.GetEnumerator();
    while (en.MoveNext())
    {
        var file = en.Current;
        var entry = Zip.CreateEntryFromFile(file.Path, dir + file.Name);                
    }

    var folders = await folder.GetFoldersAsync();
    var fEn = folders.GetEnumerator();
    while (fEn.MoveNext())
    {
        await ZipSubFolders(fEn.Current, Zip, dir + fEn.Current.Name + "/");
    }
}
0
Hack ok