Création de répertoires dans une ZipArchive C#.Net 4,5

un Zi-Parchive est une collection de zi-Parchiveentries, 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 à partir d'un système de fichiers, que vous pouvez créer l'archive dans un flux de mémoire. Mais si vous souhaitez ajouter une structure de répertoire dans l'archive, vous devez préfixer le nom d'entrée par un chemin.

Question: comment vous y prendriez-vous pour étendre ZipArchive à créer une meilleure interface pour créer et gérer des répertoires?

par exemple, la méthode courante pour ajouter un fichier à un répertoire est de 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 agréable:

var directory = _archive.CreateDirectoryEntry("directory");
var entry = _directory.CreateEntry("entryname");
24
demandé sur Meirion Hughes 2013-02-28 14:52:32

5 réponses

Vous pouvez utiliser quelque chose comme ceci, en d'autres termes, créer la structure du répertoire à 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 "/"
}
41
répondu Aimeast 2015-07-22 09:02:49

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:

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

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

7
répondu Meirion Hughes 2013-02-28 11:33:54

Si vous travaillez sur un projet qui peut utiliser plein .NET, vous pouvez essayer d'utiliser le ZipFile.CreateFromDirectory méthode, 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 nouvelles Zips à partir d'un répertoire donné.

selon le commentaire, la solution précédente ne préserve pas la structure du répertoire. Si cela est nécessaire, alors le code suivant pourrait répondre que:

    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);
        }
    }
7
répondu hmadrigal 2017-03-13 21:47:00

Utilisez l'approche récursive pour les dossiers Zip avec des sous-dossiers.

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
répondu Hack ok 2018-01-25 20:08:14

je sais je suis en retard pour la partie (7.25.2018),

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

Extension de fichier 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 emballer n'importe quoi, que c'est le fichier ou le répertoire:

using (var memoryStream = new MemoryStream()) {
    using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
        archive.CreateEntryFromAny(sourcePath);
    }
}
0
répondu Val 2018-07-25 08:43:49