2013-02-28 14 views
17

ZipArchiveはZipArchiveEntriesのコレクションであり、 "Entries"の追加/削除はうまく機能します。 しかし、ディレクトリ/ネストされた "アーカイブ"の概念はないようです。理論的には、クラスはファイルシステムから切り離されているため、アーカイブを完全にメモリストリームに作成できます。ただし、アーカイブ内にディレクトリ構造を追加する場合は、エントリ名の前にパスを付ける必要があります。ZipArchive C#.Net 4.5でのディレクトリの作成

質問: ZipArchiveを拡張してディレクトリの作成と管理のためのより良いインターフェイスを作成する方法を教えてください。たとえば、ディレクトリにファイルを追加する現在の方法は、ディレクトリ・パスのエントリを作成することです

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

これらの線に沿って何かが私にはよりよいと思われるのに対し:

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

単一のジップ内のフォルダ構造、またはジップの階層構造を意味しますか? –

+0

単一のジップ内のフォルダ構造。 –

答えて

27

あなたは手でディレクトリ構造を作成し、他の言葉で、次のようなものを使用することができます。

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

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

と使用:ここ

は、一つの可能​​な解決策である

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

しかし、おそらくネスティングの問題を予見できます。

6

あなたは完全な.NETを使用することができますプロジェクトで作業している場合は、 使用しようとすることexplained hereとしてZipFile.CreateFromDirectory方法:指定したディレクトリに基づいて新しいジッパーを作成している場合はもちろん

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

これはのみ動作します。

コメントごとに、以前の解決策ではディレクトリ構造は保持されません。それが必要な場合は、次のコードで対処することができます。

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

ちょうどこれにペタニックノート、私はいくつかの手抜きの後に見つけたもの。 Windowsのデスクトップ上では、標準的な "Sent To-> Compressed file"と同様に動作しません。 WindowsのSendToは明示的に構造内のディレクトリのエントリを作成します。このメソッドは暗黙的にディレクトリ構造を維持します。つまり、ディレクトリのエントリは作成されませんが、ディレクトリは各ファイルのフルパスにリストされます。これは、winzip関数が動作する方法を変更しません(いずれかでうまく動作します)が、特定のファイル構造を期待しているかどうかを知ることの問題です。 –

+0

ありがとうございます。たくさんの時間を節約できました。私はちょうどコードに小さな編集をしました、あなたがそれを受け入れることを願っています。 zipファイルをブラウズ可能にするために、相対パスを取得するためにSubstring(1)を追加しました。 –

0

サブフォルダを持つZip 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 + "/"); 
    } 
} 
関連する問題