2013-02-28 2 views
17

ZipArchive - это коллекция ZipArchiveEntries, и добавление/удаление «Записи» прекрасно работает. Но, похоже, нет никаких указаний о каталогах/вложенных «Архивах». Теоретически класс отделяется от файловой системы, так что вы можете полностью создать архив в потоке памяти. Но если вы хотите добавить структуру каталога в архив, вы должны префикс имени записи с помощью пути.Создание каталогов в 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 вы можете попробовать использовать в ZipFile.CreateFromDirectory метод, как 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); 
     } 
    } 
} 

конечно, это будет работать только если вы создаете новые Молнии на основе данного каталога.

В соответствии с комментарием предыдущее решение не сохраняет структуру каталогов. Если это необходимо, то следующий код может обратиться к этому:

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

Просто педантичная заметка об этом, что-то я нашел после некоторого ворчания. Он не работает * точно *, как стандартный «Отправленный To-> сжатый файл» на рабочем столе Windows. Windows SendTo будет создавать записи для каталогов в структуре явно, где, поскольку этот метод неявно поддерживает структуру каталогов, то есть он не создает записи для каталогов, но каталоги перечислены в полном пути к каждому файлу. Это не меняет способ работы функции winzip (с удовольствием работает с ними), но это всего лишь вопрос о том, что вы ожидаете определенной файловой структуры. –

+0

Спасибо. Сэкономил много времени. Я просто сделал небольшое редактирование кода, надеюсь, вы его примете. Я добавил Substring (1) для получения относительного пути, чтобы сделать zip-файл доступным для просмотра. –

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 + "/"); 
    } 
} 
Смежные вопросы