Создание каталогов в ZipArchive С#.Net 4.5
ZipArchive - это коллекция ZipArchiveEntries, и добавление/удаление "Записи" прекрасно работает.
Но, похоже, нет понятия каталогов/вложенных "Архивов". Теоретически класс отделяется от файловой системы, так что вы можете полностью создать архив в потоке памяти. Но если вы хотите добавить структуру каталога в архив, вы должны префикс имени записи с помощью пути.
Вопрос:. Как вы продвинете ZipArchive для создания лучшего интерфейса для создания и управления каталогами?
Например, текущий способ добавления файла в каталог состоит в том, чтобы создать запись с каталогом:
var entry = _archive.CreateEntry("directory/entryname");
в то время как что-то в этом направлении кажется мне более приятным:
var directory = _archive.CreateDirectoryEntry("directory");
var entry = _directory.CreateEntry("entryname");
Ответы
Ответ 1
Вы можете использовать что-то вроде следующего, другими словами, вручную создать структуру каталогов:
using (var fs = new FileStream("1.zip", FileMode.Create))
using (var zip = new ZipArchive(fs, ZipArchiveMode.Create))
{
zip.CreateEntry("12/3/"); // just end with "/"
}
Ответ 2
Если вы работаете над проектом, который может использовать полный .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);
}
}
Ответ 3
Вот одно из возможных решений:
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();
но я могу предвидеть проблемы с гнездованием, возможно.
Ответ 4
Я знаю, что опаздываю на вечеринку (7.25.2018),
это работает безупречно для меня, даже с рекурсивными каталогами.
Во-первых, не забудьте установить пакет NuGet:
Install-Package System.IO.Compression
А затем файл расширения для 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) {
archive.CreateEntryFromAny(file, entryName);
}
}
}
И затем вы можете упаковать что угодно, будь то файл или каталог:
using (var memoryStream = new MemoryStream()) {
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
archive.CreateEntryFromAny(sourcePath);
}
}
Ответ 5
Используйте рекурсивный подход к 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 + "/");
}
}