38

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

質問: ZipArchive を拡張して、ディレクトリを作成および管理するためのより優れたインターフェイスを作成するにはどうすればよいですか?

たとえば、ディレクトリにファイルを追加する現在の方法は、ディレクトリ パスを使用してエントリを作成することです。

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

一方、これらの線に沿ったものは私にとってより良いようです:

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

11 に答える 11

9

完全な .NET を使用できるプロジェクトで作業している場合は、ここで説明されているように、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);
        }
    }
}

もちろん、これは、特定のディレクトリに基づいて新しい Zip を作成している場合にのみ機能します。

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

    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);
        }
    }
于 2014-10-21T16:19:30.597 に答える
7

考えられる解決策の 1 つを次に示します。

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

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

于 2013-02-28T11:15:54.830 に答える
2

@Andreyからの非常に良いアプローチの少しの変更

public static void CreateEntryFromDirectory2(this ZipArchive archive, string sourceDirName, CompressionLevel compressionLevel = CompressionLevel.Fastest)
    {
        var folders = new Stack<string>();

        folders.Push(sourceDirName);

        do
        {
            var currentFolder = folders.Pop();

            foreach (var item in Directory.GetFiles(currentFolder))
            {
                archive.CreateEntryFromFile(item, item.Substring(sourceDirName.Length + 1), compressionLevel);
            }

            foreach (var item in Directory.GetDirectories(currentFolder))
            {
                folders.Push(item);
            }
        } 
        while (folders.Count > 0);
    }
于 2021-02-13T22:36:32.387 に答える
0

それは私のために働いています。

静的クラス

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

        if (files.Any())
        {

            foreach (var file in files)
            {
                archive.CreateEntryFromAny(file, entryName);
            }
        }
        else
        {
            if (!string.IsNullOrEmpty(entryName) && entryName[entryName.Length - 1] != '/')
            {
                entryName += "\\";
            }
            archive.CreateEntry(entryName);
        }
        
    }
}

そのようなメソッドを呼び出す

            byte[] archiveFile;

            using (var memoryStream = new MemoryStream())
            {
                using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
                {
                        archive.CreateEntryFromAny(file.Path);

                }
                archiveFile = memoryStream.ToArray();
            }
于 2021-12-08T05:34:43.847 に答える