2013-02-28 14 views
17

Ein ZipArchiv ist eine Sammlung von ZipArchiveEntries, und Hinzufügen/Entfernen von "Entries" funktioniert gut. Aber es scheint, dass es keine Vorstellung von Verzeichnissen/verschachtelten "Archives" gibt. Theoretisch ist die Klasse von einem Dateisystem entkoppelt, indem Sie das Archiv vollständig in einem Speicherstream erstellen können. Wenn Sie jedoch eine Verzeichnisstruktur innerhalb des Archivs hinzufügen möchten, müssen Sie dem Eintragsnamen einen Pfad voranstellen.Erstellen von Verzeichnissen in einem ZipArchiv C# .Net 4.5

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

Zum Beispiel die aktuelle Methode eine Datei in ein Verzeichnis hinzuzufügen, ist die Eingabe mit dem Verzeichnispfad zu erstellen:

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

während etwas in dieser Richtung scheint schöner zu mir:

var directory = _archive.CreateDirectoryEntry("directory"); 
var entry = _directory.CreateEntry("entryname"); 
+0

Meinst du eine Ordnerstruktur in einem einzigen Reißverschluss oder eine Hierarchie von Reißverschlüssen? –

+0

Ordnerstruktur in einem einzigen Zip. –

Antwort

27

Sie können so etwas wie die folgenden, in anderen Worten verwenden, die Verzeichnisstruktur von Hand 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 "/" 
} 
6
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 gebraucht:

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

aber ich kann vielleicht Probleme mit der Verschachtelung sehen, vielleicht.

6

Wenn Sie an einem Projekt arbeiten, das volle .NET verwenden können, können Sie versuchen die verwenden ZipFile.CreateFromDirectory Verfahren, wie explained here:

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

natürlich wird dies nur funktionieren, wenn Sie neue Zips auf einem bestimmten Verzeichnis basiert erstellen.

Laut dem Kommentar behält die vorherige Lösung die Verzeichnisstruktur nicht bei. Wenn das erforderlich ist, dann kann der folgende Code die Adresse:

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

Nur eine pedantische Notiz dazu, etwas, das ich nach einigem Herumspielen gefunden habe. Es funktioniert nicht * genau * als Standard "Gesendet an-> Komprimierte Datei" auf einem Windows-Desktop. Windows SendTo erstellt explizit Einträge für die Verzeichnisse in der Struktur, wobei diese Methode die Verzeichnisstruktur implizit beibehält, d. H. Sie erstellt keine Einträge für die Verzeichnisse, sondern Verzeichnisse werden im vollständigen Pfad zu jeder Datei aufgelistet. Es ändert nichts an der Art, wie die Winzip-Funktion funktioniert (es macht Spaß, mit beiden zu arbeiten), aber es ist nur eine Frage des Bewusstseins, ob Sie eine bestimmte Dateistruktur erwarten. –

+0

Danke. Sparte mir viel Zeit. Ich habe nur eine kleine Änderung am Code vorgenommen, hoffe, Sie akzeptieren es. Ich habe Substring (1) hinzugefügt, um den relativen Pfad zu erhalten, um die Zip-Datei durchsuchbar zu machen. –

0

Verwenden Sie die rekursive Ansatz Ordner mit Unterordnern zu sehen lassen.

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 + "/"); 
    } 
} 
Verwandte Themen