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
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>10.1.2-beta01</Version>
<Version>10.1.2</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
102 changes: 93 additions & 9 deletions src/BootstrapBlazor/Services/DefaultZipArchiveService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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
Expand Down Expand Up @@ -29,12 +29,12 @@ public async Task<Stream> ArchiveAsync(IEnumerable<string> files, ArchiveOptions
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFileName">归档文件</param>
/// <param name="archiveFile">归档文件</param>
/// <param name="files">要归档的文件集合</param>
/// <param name="options">归档配置</param>
public async Task ArchiveAsync(string archiveFileName, IEnumerable<string> files, ArchiveOptions? options = null)
public async Task ArchiveAsync(string archiveFile, IEnumerable<string> files, ArchiveOptions? options = null)
{
using var stream = File.OpenWrite(archiveFileName);
using var stream = File.OpenWrite(archiveFile);
await ArchiveFilesAsync(stream, files, options);
}

Expand All @@ -61,23 +61,79 @@ private static async Task ArchiveFilesAsync(Stream stream, IEnumerable<string> f
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFileName">归档文件</param>
/// <param name="directoryName">要归档文件夹</param>
/// <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 archiveFileName, string directoryName, CompressionLevel compressionLevel = CompressionLevel.Optimal, bool includeBaseDirectory = false, Encoding? encoding = null)
public async Task ArchiveDirectory(string archiveFile, string directoryName, CompressionLevel compressionLevel = CompressionLevel.Optimal, bool includeBaseDirectory = false, Encoding? encoding = null, CancellationToken token = default)
{
if (Directory.Exists(directoryName))
{
var folder = Path.GetDirectoryName(archiveFileName);
var folder = Path.GetDirectoryName(archiveFile);
if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
await Task.Run(() => ZipFile.CreateFromDirectory(directoryName, archiveFileName, compressionLevel, includeBaseDirectory, encoding));
#if NET10_0_OR_GREATER
await ZipFile.CreateFromDirectoryAsync(directoryName, archiveFile, compressionLevel, includeBaseDirectory, encoding, token);
#else
await Task.Run(() =>
{
token.ThrowIfCancellationRequested();
ZipFile.CreateFromDirectory(directoryName, archiveFile, compressionLevel, includeBaseDirectory, encoding);
}, token);
#endif
}
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="entries"></param>
Comment thread
ArgoZhang marked this conversation as resolved.
/// <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);
}
}
Comment thread
ArgoZhang marked this conversation as resolved.
}

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))
{
Comment thread
ArgoZhang marked this conversation as resolved.
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));
Comment thread
ArgoZhang marked this conversation as resolved.
Comment thread
ArgoZhang marked this conversation as resolved.
AddFolderToZip(archive, subfolderPath, newRelativePath, compressionLevel);
}
}

Expand All @@ -99,6 +155,34 @@ public bool ExtractToDirectory(string archiveFile, string destinationDirectoryNa
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))
{
Directory.CreateDirectory(destinationDirectoryName);
}

#if NET10_0_OR_GREATER
await ZipFile.ExtractToDirectoryAsync(archiveFile, destinationDirectoryName, encoding, overwriteFiles, token);
#else
await Task.Run(() =>
{
token.ThrowIfCancellationRequested();
ZipFile.ExtractToDirectory(archiveFile, destinationDirectoryName, encoding, overwriteFiles);
}, token);
#endif
return true;
}

/// <summary>
/// <inheritdoc/>
/// </summary>
Expand Down
40 changes: 32 additions & 8 deletions src/BootstrapBlazor/Services/IZipArchiveService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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
Expand All @@ -24,21 +24,34 @@ public interface IZipArchiveService
/// <summary>
/// 将文件归档方法
/// </summary>
/// <param name="archiveFileName">归档文件</param>
/// <param name="archiveFile">归档文件</param>
/// <param name="files">要归档的文件集合</param>
/// <param name="options">归档配置</param>
Task ArchiveAsync(string archiveFileName, IEnumerable<string> files, ArchiveOptions? options = null);
Task ArchiveAsync(string archiveFile, IEnumerable<string> files, ArchiveOptions? options = null);

/// <summary>
/// 将指定目录归档方法
/// </summary>
/// <param name="archiveFileName">归档文件</param>
/// <param name="archiveFile">归档文件</param>
/// <param name="directoryName">要归档文件夹</param>
/// <param name="compressionLevel"></param>
/// <param name="includeBaseDirectory"></param>
/// <param name="encoding"></param>
/// <param name="compressionLevel">压缩率</param>
/// <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>
/// 将指定目录归档方法
Comment thread
ArgoZhang marked this conversation as resolved.
/// </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 archiveFileName, string directoryName, CompressionLevel compressionLevel = CompressionLevel.Optimal, bool includeBaseDirectory = false, Encoding? encoding = null);
Task ArchiveDirectory(string archiveFile, IEnumerable<string> entries, CompressionLevel compressionLevel = CompressionLevel.Optimal, Encoding? encoding = null, bool skipEmptyFolder = false, CancellationToken token = default);

/// <summary>
/// 解压缩归档文件到指定文件夹
Expand All @@ -50,6 +63,17 @@ public interface IZipArchiveService
/// <returns></returns>
bool ExtractToDirectory(string archiveFile, string destinationDirectoryName, bool overwriteFiles = false, Encoding? encoding = null);

/// <summary>
/// 解压缩归档文件到指定文件夹异步方法
/// </summary>
/// <param name="archiveFile">归档文件</param>
/// <param name="destinationDirectoryName">解压缩文件夹</param>
/// <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>
/// 获得归档压缩文件中指定归档文件
/// </summary>
Expand Down
30 changes: 30 additions & 0 deletions test/UnitTest/Services/ZipArchiveServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public async Task Archive_Ok()
archService.ExtractToDirectory(archiveFile, destFolder);
Assert.True(Directory.Exists(destFolder));

// 删除文件夹
Directory.Delete(destFolder, true);
Assert.False(Directory.Exists(destFolder));

// 异步解压缩单元测试
await archService.ExtractToDirectoryAsync(archiveFile, destFolder);
Assert.True(Directory.Exists(destFolder));

// 打包文件夹单元测试
var tempFolder = Path.Combine(root, "test_temp");
if (Directory.Exists(tempFolder))
Expand All @@ -67,5 +75,27 @@ public async Task Archive_Ok()
File.Delete(destFile);

await Assert.ThrowsAsync<ArgumentNullException>(() => archService.ArchiveDirectory(null!, destFolder, includeBaseDirectory: true));

// 测试压缩多个文件夹
var entries = new List<string>()
{
destFolder,
tempFolder,
};
entries.AddRange(files);

destFile = Path.Combine(root, "folder.zip");
if (File.Exists(destFile))
{
File.Delete(destFile);
}
Assert.False(File.Exists(destFile));
var subFolder = Path.Combine(tempFolder, "sub");
if (!Directory.Exists(subFolder))
{
Directory.CreateDirectory(subFolder);
}
await archService.ArchiveDirectory(destFile, entries);
Assert.True(File.Exists(destFile));
}
}