it-swarm.com.ru

Создание каталогов в ZipArchive C # .Net 4.5

ZipArchive - это коллекция ZipArchiveEntries, и добавление/удаление «Entries» работает хорошо .. Но, похоже, нет понятия каталогов/вложенных «Archives». Теоретически, класс отделен от файловой системы, в которой вы можете полностью создать архив в потоке памяти. Но если вы хотите добавить структуру каталогов в архиве, вы должны поставить перед именем записи префикс. 

Вопрос: Как бы вы расширили ZipArchive для создания лучшего интерфейса для создания каталогов и управления ими?

Например, текущий метод добавления файла в каталог - создать запись с путем к каталогу:

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

тогда как что-то в этом роде мне кажется более приятным: 

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

Вы можете использовать что-то вроде следующего, другими словами, создать структуру каталогов вручную:

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

Если вы работаете над проектом, который может использовать полноценный .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);
        }
    }
}

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

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

    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

Вот одно из возможных решений: 

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

но я могу предвидеть проблемы с вложением, возможно. 

7
Meirion Hughes

Я знаю, что опоздал на вечеринку (7.25.2018),

Но это работает для меня безупречно, даже с рекурсивным каталогом.

Файл расширения для 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);
        }
    }

}

И тогда вы можете упаковать что угодно, будь то файл или каталог:

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

Используйте рекурсивный подход к папкам Zip с подпапками.

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