Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/BootstrapBlazor/Services/ArchiveEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone

using System.IO.Compression;

/// <summary>
/// 归档项实体类
/// </summary>
public readonly record struct ArchiveEntry
{
/// <summary>
/// 获得 物理文件
/// </summary>
public string SourceFileName { get; init; }

/// <summary>
/// 获得 归档项
/// </summary>
public string EntryName { get; init; }

/// <summary>
/// 获得 压缩配置
/// </summary>
public CompressionLevel? CompressionLevel { get; init; }
}
126 changes: 24 additions & 102 deletions src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,63 +13,61 @@ class DefaultZipArchiveService : IZipArchiveService
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="files">要归档的文件集合</param>
/// <param name="options">归档配置</param>
/// <returns>归档数据流</returns>
public async Task<Stream> ArchiveAsync(IEnumerable<string> files, ArchiveOptions? options = null)
public async Task<Stream> ArchiveAsync(IEnumerable<ArchiveEntry> entries, ArchiveOptions? options = null)
{
var stream = new MemoryStream();
options ??= new ArchiveOptions();
options.LeaveOpen = true;
await ArchiveFilesAsync(stream, files, options);
await ArchiveFilesAsync(stream, entries, options);
stream.Position = 0;
return stream;
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="files">要归档的文件集合</param>
/// <param name="options">归档配置</param>
public async Task ArchiveAsync(string archiveFile, IEnumerable<string> files, ArchiveOptions? options = null)
public async Task ArchiveAsync(string archiveFile, IEnumerable<ArchiveEntry> entries, ArchiveOptions? options = null)
{
using var stream = File.OpenWrite(archiveFile);
await ArchiveFilesAsync(stream, files, options);
await ArchiveFilesAsync(stream, entries, options);
}

private static async Task ArchiveFilesAsync(Stream stream, IEnumerable<string> files, ArchiveOptions? options = null)
private static async Task ArchiveFilesAsync(Stream stream, IEnumerable<ArchiveEntry> entries, ArchiveOptions? options = null)
{
options ??= new ArchiveOptions();
using var archive = new ZipArchive(stream, options.Mode, options.LeaveOpen, options.Encoding);
foreach (var f in files)
foreach (var f in entries)
{
if (options.ReadStreamAsync != null)
{
var entry = archive.CreateEntry(Path.GetFileName(f), options.CompressionLevel);
using var entryStream = entry.Open();
await using var content = await options.ReadStreamAsync(f);
var entry = archive.CreateEntry(f.EntryName, options.CompressionLevel);
await using var content = await options.ReadStreamAsync(f.SourceFileName);
await using var entryStream = entry.Open();
await content.CopyToAsync(entryStream);
}
Comment thread
ArgoZhang marked this conversation as resolved.
else
else if (Directory.Exists(f.SourceFileName))
{
archive.CreateEntryFromFile(f, Path.GetFileName(f), options.CompressionLevel);
var entryName = f.EntryName;
if (!string.IsNullOrEmpty(entryName))
{
if (!entryName.EndsWith('/'))
{
entryName = $"{entryName}/";
}
archive.CreateEntry(entryName, f.CompressionLevel ?? options.CompressionLevel);
}
}
else if (File.Exists(f.SourceFileName))
{
archive.CreateEntryFromFile(f.SourceFileName, f.EntryName, f.CompressionLevel ?? options.CompressionLevel);
Comment thread
ArgoZhang marked this conversation as resolved.
Comment thread
ArgoZhang marked this conversation as resolved.
Comment thread
ArgoZhang marked this conversation as resolved.
}
}
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFile"></param>
/// <param name="directoryName"></param>
/// <param name="compressionLevel"></param>
/// <param name="includeBaseDirectory"></param>
/// <param name="encoding"></param>
/// <param name="token"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task ArchiveDirectory(string archiveFile, string directoryName, CompressionLevel compressionLevel = CompressionLevel.Optimal, bool includeBaseDirectory = false, Encoding? encoding = null, CancellationToken token = default)
public async Task ArchiveDirectoryAsync(string archiveFile, string directoryName, CompressionLevel compressionLevel = CompressionLevel.Optimal, bool includeBaseDirectory = false, Encoding? encoding = null, CancellationToken token = default)
{
if (Directory.Exists(directoryName))
{
Expand All @@ -93,77 +91,6 @@ await Task.Run(() =>
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="entries"></param>
/// <param name="compressionLevel"></param>
/// <param name="encoding"></param>
/// <param name="skipEmptyFolder"></param>
/// <param name="token"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task ArchiveDirectory(string archiveFile, IEnumerable<string> entries, CompressionLevel compressionLevel = CompressionLevel.Optimal, Encoding? encoding = null, bool skipEmptyFolder = false, CancellationToken token = default)
{
using var archive = ZipFile.Open(archiveFile, ZipArchiveMode.Create, encoding);

foreach (var entry in entries)
{
if (Directory.Exists(entry))
{
AddFolderToZip(archive, entry, Path.GetFileName(entry), compressionLevel);
}
else if (File.Exists(entry))
{
archive.CreateEntryFromFile(entry, Path.GetFileName(entry), compressionLevel);
}
}
}

private static void AddFolderToZip(ZipArchive archive, string folderPath, string relativePath, CompressionLevel compressionLevel = CompressionLevel.Optimal)
{
archive.CreateEntry($"{relativePath}/", compressionLevel);

// 添加当前文件夹中的所有文件
foreach (string filePath in Directory.GetFiles(folderPath))
{
string entryName = Path.Combine(relativePath, Path.GetFileName(filePath));
archive.CreateEntryFromFile(filePath, entryName, compressionLevel);
}

// 递归添加所有子文件夹
foreach (string subfolderPath in Directory.GetDirectories(folderPath))
{
string newRelativePath = Path.Combine(relativePath, Path.GetFileName(subfolderPath));
AddFolderToZip(archive, subfolderPath, newRelativePath, compressionLevel);
}
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="destinationDirectoryName">解压缩文件夹</param>
/// <param name="overwriteFiles">是否覆盖文件 默认 false 不覆盖</param>
/// <param name="encoding">编码方式 默认 null 内部使用 UTF-8</param>
/// <returns></returns>
public bool ExtractToDirectory(string archiveFile, string destinationDirectoryName, bool overwriteFiles = false, Encoding? encoding = null)
{
if (!Directory.Exists(destinationDirectoryName))
{
Directory.CreateDirectory(destinationDirectoryName);
}
ZipFile.ExtractToDirectory(archiveFile, destinationDirectoryName, encoding, overwriteFiles);
return true;
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFile"></param>
/// <param name="destinationDirectoryName"></param>
/// <param name="overwriteFiles"></param>
/// <param name="encoding"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<bool> ExtractToDirectoryAsync(string archiveFile, string destinationDirectoryName, bool overwriteFiles = false, Encoding? encoding = null, CancellationToken token = default)
{
if (!Directory.Exists(destinationDirectoryName))
Expand All @@ -186,11 +113,6 @@ await Task.Run(() =>
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="entryFile">解压缩文件</param>
/// <param name="overwriteFiles">是否覆盖文件 默认 false 不覆盖</param>
/// <param name="encoding">编码方式 默认 null 内部使用 UTF-8</param>
/// <returns></returns>
public ZipArchiveEntry? GetEntry(string archiveFile, string entryFile, bool overwriteFiles = false, Encoding? encoding = null)
{
using var archive = ZipFile.Open(archiveFile, ZipArchiveMode.Read, encoding);
Expand Down
35 changes: 5 additions & 30 deletions src/BootstrapBlazor/Services/IZipArchiveService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ public interface IZipArchiveService
/// <summary>
/// 将文件归档方法
/// </summary>
/// <param name="files">要归档的文件集合</param>
/// <param name="entries">要归档项集合</param>
/// <param name="options">归档配置</param>
/// <returns>归档数据流</returns>
Task<Stream> ArchiveAsync(IEnumerable<string> files, ArchiveOptions? options = null);
Task<Stream> ArchiveAsync(IEnumerable<ArchiveEntry> entries, ArchiveOptions? options = null);

/// <summary>
/// 将文件归档方法
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="files">要归档的文件集合</param>
/// <param name="entries">要归档项集合</param>
/// <param name="options">归档配置</param>
Task ArchiveAsync(string archiveFile, IEnumerable<string> files, ArchiveOptions? options = null);
Task ArchiveAsync(string archiveFile, IEnumerable<ArchiveEntry> entries, ArchiveOptions? options = null);

/// <summary>
/// 将指定目录归档方法
Expand All @@ -38,30 +38,7 @@ public interface IZipArchiveService
/// <param name="includeBaseDirectory">是否包含本目录 默认 false</param>
/// <param name="encoding">编码方式 默认 null 内部使用 UTF-8</param>
/// <param name="token"></param>
/// <returns></returns>
Task ArchiveDirectory(string archiveFile, string directoryName, CompressionLevel compressionLevel = CompressionLevel.Optimal, bool includeBaseDirectory = false, Encoding? encoding = null, CancellationToken token = default);

/// <summary>
/// 将指定目录归档方法
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="entries">要归档条目</param>
/// <param name="compressionLevel">压缩率</param>
/// <param name="encoding">编码方式 默认 null 内部使用 UTF-8</param>
/// <param name="skipEmptyFolder">是否跳过空文件夹</param>
/// <param name="token"></param>
/// <returns></returns>
Task ArchiveDirectory(string archiveFile, IEnumerable<string> entries, CompressionLevel compressionLevel = CompressionLevel.Optimal, Encoding? encoding = null, bool skipEmptyFolder = false, CancellationToken token = default);

/// <summary>
/// 解压缩归档文件到指定文件夹
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="destinationDirectoryName">解压缩文件夹</param>
/// <param name="overwriteFiles">是否覆盖文件 默认 false 不覆盖</param>
/// <param name="encoding">编码方式 默认 null 内部使用 UTF-8</param>
/// <returns></returns>
bool ExtractToDirectory(string archiveFile, string destinationDirectoryName, bool overwriteFiles = false, Encoding? encoding = null);
Task ArchiveDirectoryAsync(string archiveFile, string directoryName, CompressionLevel compressionLevel = CompressionLevel.Optimal, bool includeBaseDirectory = false, Encoding? encoding = null, CancellationToken token = default);

/// <summary>
/// 解压缩归档文件到指定文件夹异步方法
Expand All @@ -71,7 +48,6 @@ public interface IZipArchiveService
/// <param name="overwriteFiles">是否覆盖文件 默认 false 不覆盖</param>
/// <param name="encoding">编码方式 默认 null 内部使用 UTF-8</param>
/// <param name="token"></param>
/// <returns></returns>
Task<bool> ExtractToDirectoryAsync(string archiveFile, string destinationDirectoryName, bool overwriteFiles = false, Encoding? encoding = null, CancellationToken token = default);

/// <summary>
Expand All @@ -81,6 +57,5 @@ public interface IZipArchiveService
/// <param name="entryFile">解压缩文件</param>
/// <param name="overwriteFiles">是否覆盖文件 默认 false 不覆盖</param>
/// <param name="encoding">编码方式 默认 null 内部使用 UTF-8</param>
/// <returns></returns>
ZipArchiveEntry? GetEntry(string archiveFile, string entryFile, bool overwriteFiles = false, Encoding? encoding = null);
}
Loading