Skip to content
This repository was archived by the owner on Jan 25, 2026. It is now read-only.

Commit 40bc035

Browse files
committed
feat(file-service): 添加压缩文件任务实现
1 parent b8889f2 commit 40bc035

File tree

5 files changed

+90
-13
lines changed

5 files changed

+90
-13
lines changed

Model/Files/FileItem.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using System.Collections.Generic;
22
using System.IO;
3-
using System.Linq;
4-
using PCL.Core.Helper;
53
using PCL.Core.Service;
64

75
namespace PCL.Core.Model.Files;
@@ -57,15 +55,16 @@ public record FileItem(
5755
public string? TargetDirectory
5856
{
5957
get => _targetDirectory;
60-
set => _targetDirectory = (value == null) ? null : Path.GetFullPath(Path.Combine(FileService.DefaultDirectory, value));
58+
set => _targetDirectory = (value == null) ? null : Path.Combine(FileService.DefaultDirectory, value);
6159
}
6260

6361
private string? _targetPath;
6462

6563
/// <summary>
6664
/// The path to storage the file.<br/>
67-
/// If <see cref="TargetDirectory"/> has been set, return the path relative to it,
68-
/// otherwise return a combined path by <see cref="Type"/> and <see cref="Name"/>
65+
/// If <see cref="TargetDirectory"/> has been set, return the path with <see cref="Name"/> relative to it;
66+
/// if the value has been set manually, return the value directly;
67+
/// otherwise return a combined path depends on <see cref="Type"/> and <see cref="Name"/>.
6968
/// </summary>
7069
public string TargetPath
7170
{
@@ -87,6 +86,7 @@ public string TargetPath
8786
_targetPath = value;
8887
return value;
8988
}
89+
set => _targetPath = Path.Combine(FileService.DefaultDirectory, value);
9090
}
9191

9292
public override int GetHashCode() => TargetPath.GetHashCode();

Model/Files/IFileTask.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ public interface IFileTask
1414

1515
public bool OnProcessFinished(FileItem item, object? result);
1616

17-
public void OnTaskFinished();
17+
public void OnTaskFinished(object? result);
1818
}

PCL.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
<Compile Include="Utils\ExpandoObjectConverter.cs" />
195195
<Compile Include="Utils\FileTask\FileTask.cs" />
196196
<Compile Include="Utils\FileTask\MatchableFileTask.cs" />
197+
<Compile Include="Utils\FileTask\ZipFileTask.cs" />
197198
<Compile Include="Utils\FileVersionControl\FileVersionObjects.cs" />
198199
<Compile Include="Utils\FileVersionControl\FileVersionObjectsComparer.cs" />
199200
<Compile Include="Utils\FileVersionControl\IVersionControl.cs" />

Utils/FileTask/FileTask.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ public FileTask(bool ignoreResult = false) : this([], ignoreResult) { }
3535
public FileTask(params FileItem[] items) : this(items.AsEnumerable()) { }
3636

3737
/// <summary>
38-
/// Event invoked after a process finished
38+
/// Event invoked with the finished item and the result after a process finished
3939
/// </summary>
4040
public event Action<FileItem, object?>? ProcessFinished;
4141

4242
/// <summary>
43-
/// Event invoked after the task finished
43+
/// Event invoked with the result after the task finished
4444
/// </summary>
45-
public event Action? TaskFinished;
45+
public event Action<object?>? TaskFinished;
4646

4747
#region Implementation
4848

@@ -52,15 +52,14 @@ public FileTask(params FileItem[] items) : this(items.AsEnumerable()) { }
5252

5353
public virtual bool OnProcessFinished(FileItem item, object? result)
5454
{
55-
if (IgnoreResult) return true;
56-
if (ProcessFinished == null) return false;
55+
if (ProcessFinished == null) return IgnoreResult;
5756
ProcessFinished.Invoke(item, result);
5857
return true;
5958
}
6059

61-
public virtual void OnTaskFinished()
60+
public virtual void OnTaskFinished(object? result)
6261
{
63-
TaskFinished?.Invoke();
62+
TaskFinished?.Invoke(result);
6463
}
6564

6665
#endregion

Utils/FileTask/ZipFileTask.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using ICSharpCode.SharpZipLib.Zip;
5+
using PCL.Core.Model.Files;
6+
7+
namespace PCL.Core.Utils.FileTask;
8+
9+
/// <summary>
10+
/// 若写入压缩文件过程中抛出异常,将会抛出该异常,并将原异常作为 <see cref="Exception.InnerException"/> 提供。
11+
/// </summary>
12+
public class ZipFileTaskException(Exception innerException) : Exception(innerException.Message, innerException);
13+
14+
/// <summary>
15+
/// 用于创建 ZIP 格式归档的文件任务。
16+
/// </summary>
17+
/// <param name="zipPath">参考 <see cref="ZipPath"/></param>
18+
/// <param name="items">归档包含的文件</param>
19+
public class ZipFileTask(string zipPath, IEnumerable<FileItem> items) : FileTask(items, true)
20+
{
21+
/// <summary>
22+
/// ZIP 文件的路径。若该路径已存在,写入时默认直接覆盖原文件,该行为可以通过 <see cref="OpenFileMode"/> 指定。
23+
/// </summary>
24+
public string ZipPath { get; } = zipPath;
25+
26+
/// <summary>
27+
/// 压缩等级。取值范围为 0~9,默认为 3。
28+
/// </summary>
29+
public int ZipLevel { get; set; } = 3;
30+
31+
public bool DeleteWhenException { get; set; } = true;
32+
33+
/// <summary>
34+
/// 写入 ZIP 文件时使用的 <see cref="FileMode"/>。
35+
/// </summary>
36+
public FileMode OpenFileMode { get; set; } = FileMode.Create;
37+
38+
/// <summary>
39+
/// 写入 ZIP 文件时使用的 <see cref="FileShare"/>。
40+
/// </summary>
41+
public FileShare OpenFileShare { get; set; } = FileShare.None;
42+
43+
private readonly List<FileItem> _filesToArchive = [];
44+
45+
public override bool OnProcessFinished(FileItem item, object? result)
46+
{
47+
_filesToArchive.Add(item);
48+
return base.OnProcessFinished(item, result);
49+
}
50+
51+
public override void OnTaskFinished(object? result)
52+
{
53+
var fileCreated = false;
54+
try
55+
{
56+
using var zipFile = File.Open(ZipPath, OpenFileMode, FileAccess.Write, OpenFileShare);
57+
fileCreated = true;
58+
using var zipStream = new ZipOutputStream(zipFile);
59+
zipStream.SetLevel(ZipLevel);
60+
foreach (var item in _filesToArchive)
61+
{
62+
var entryName = ZipEntry.CleanName(item.Name);
63+
zipStream.PutNextEntry(new ZipEntry(entryName));
64+
using var fileInput =
65+
File.Open(item.TargetPath, FileMode.Open, FileAccess.Read, FileShare.Read);
66+
fileInput.CopyTo(zipStream);
67+
zipStream.CloseEntry();
68+
}
69+
zipStream.Finish();
70+
}
71+
catch (Exception ex)
72+
{
73+
if (fileCreated && DeleteWhenException) File.Delete(ZipPath);
74+
throw new ZipFileTaskException(ex);
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)