wake-up-neo.net

Erstellen von Verzeichnissen in einem ZipArchive C # .Net 4.5

Ein ZipArchiv ist eine Sammlung von ZipArchiveEntries, und das Hinzufügen/Entfernen von "Einträgen" funktioniert gut . Es scheint jedoch keine Ahnung von Verzeichnissen/verschachtelten Archiven zu geben. Theoretisch ist die Klasse von einem Dateisystem entkoppelt, indem Sie das Archiv vollständig in einem Speicherstrom erstellen können. Wenn Sie jedoch eine Verzeichnisstruktur im Archiv hinzufügen möchten, müssen Sie dem Eintragsnamen einen Pfad voranstellen. 

Frage: Wie würden Sie ZipArchive erweitern, um eine bessere Schnittstelle zum Erstellen und Verwalten von Verzeichnissen zu erstellen?

Die aktuelle Methode zum Hinzufügen einer Datei zu einem Verzeichnis besteht beispielsweise darin, den Eintrag mit dem Verzeichnispfad zu erstellen:

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

wobei mir etwas in dieser Richtung netter erscheint: 

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

Sie können etwas wie das Folgende verwenden, dh die Verzeichnisstruktur manuell erstellen:

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

Wenn Sie an einem Projekt arbeiten, das vollständig .NET verwenden kann, können Sie versuchen, die ZipFile.CreateFromDirectory-Methode zu verwenden, wie hier erklärt :

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);
        }
    }
}

Dies funktioniert natürlich nur, wenn Sie neue Zips auf der Grundlage eines bestimmten Verzeichnisses erstellen.

Gemäß dem Kommentar behält die vorherige Lösung die Verzeichnisstruktur nicht bei. Wenn dies erforderlich ist, kann der folgende Code das Problem beheben:

    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

Hier ist eine mögliche Lösung: 

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);
    }
}

und verwendet: 

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

aber ich kann vielleicht Probleme beim Schachteln vorhersehen. 

7
Meirion Hughes

Ich weiß, ich bin zu spät zur Party (7.25.2018),

Dies funktioniert jedoch einwandfrei für mich, selbst bei rekursiven Verzeichnissen.

Erweiterungsdatei für 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);
        }
    }

}

Und dann können Sie alles packen, egal ob es sich um eine Datei oder ein Verzeichnis handelt:

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

Verwenden Sie den rekursiven Ansatz für Zip-Ordner mit Unterordnern.

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