forked from BeyondDimension/SteamTools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTarGZipHelper.cs
More file actions
160 lines (146 loc) · 5.82 KB
/
TarGZipHelper.cs
File metadata and controls
160 lines (146 loc) · 5.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip.Compression;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using CC = System.Common.Constants;
namespace System.Application
{
public static class TarGZipHelper
{
/// <summary>
/// 创建压缩包文件
/// </summary>
/// <param name="filePath">要创建的文件路径</param>
/// <param name="dirPath">要打包的目录</param>
/// <param name="level">压缩等级,取值范围在 <see cref="Deflater.NO_COMPRESSION"/> ~ <see cref="Deflater.BEST_COMPRESSION"/></param>
/// <param name="progress">进度值监听</param>
/// <returns></returns>
public static bool Create(string filePath, string dirPath, int level = Deflater.BEST_COMPRESSION, ProgressMessageHandler? progress = null)
{
if (!filePath.EndsWith(FileEx.TAR_GZ)) filePath += FileEx.TAR_GZ;
if (File.Exists(filePath)) return false;
if (!Directory.Exists(dirPath)) return false;
using var fs = File.Create(filePath);
using var s = new GZipOutputStream(fs);
s.SetLevel(level);
using var archive = TarArchive.CreateOutputTarArchive(s, TarBuffer.DefaultBlockFactor, EncodingCache.UTF8NoBOM);
if (progress != null) archive.ProgressMessageEvent += progress;
HandleFiles(dirPath);
HandleDirs(dirPath);
void HandleFiles(string dirPath_)
{
foreach (var file in Directory.GetFiles(dirPath_))
{
var entry = TarEntry.CreateEntryFromFile(file);
entry.Name = file.TrimStart(dirPath).Trim(Path.DirectorySeparatorChar);
if (Path.DirectorySeparatorChar != IOPath.UnixDirectorySeparatorChar)
entry.Name = entry.Name.Replace(Path.DirectorySeparatorChar, IOPath.UnixDirectorySeparatorChar);
archive.WriteEntry(entry, false);
}
}
void HandleDirs(string dirPath_)
{
foreach (var dir in Directory.GetDirectories(dirPath_))
{
HandleFiles(dir);
}
}
return true;
}
/// <summary>
/// 解压压缩包文件
/// </summary>
/// <param name="filePath">要解压的压缩包文件路径</param>
/// <param name="dirPath">要解压的文件夹路径,文件夹必须不存在</param>
/// <param name="progressMessage">进度消息监听</param>
/// <param name="progress">进度值监听</param>
/// <param name="maxProgress"></param>
/// <returns></returns>
public static bool Unpack(string filePath, string dirPath,
ProgressMessageHandler? progressMessage = null,
IProgress<float>? progress = null,
float maxProgress = CC.MaxProgress)
{
if (!File.Exists(filePath)) return false;
if (Directory.Exists(dirPath)) return false;
using var fs = File.OpenRead(filePath);
// 只能用 FileStream 的长度,GZipInputStream.Length 会引发异常
// https://github.com/icsharpcode/SharpZipLib/blob/v1.3.1/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs#L542
float length = fs.Length;
var isFinish = false;
CancellationTokenSource? cts = null;
async void ProgressMonitor()
{
try
{
while (!isFinish)
{
var value = fs.Position / length * maxProgress;
progress!.Report(value);
await Task.Delay(200, cts.Token);
}
}
catch (OperationCanceledException)
{
}
}
Directory.CreateDirectory(dirPath);
using var s = new GZipInputStream(fs);
using var archive = TarArchive.CreateInputTarArchive(s, EncodingCache.UTF8NoBOM);
if (progressMessage != null) archive.ProgressMessageEvent += progressMessage;
var hasProgress = progress != null;
if (hasProgress)
{
cts = new();
try
{
Task.Factory.StartNew(ProgressMonitor, cts.Token);
}
catch (OperationCanceledException)
{
}
}
archive.ExtractContents(dirPath);
isFinish = true;
if (hasProgress)
{
cts!.Cancel();
progress!.Report(maxProgress);
}
return true;
}
}
#if DEBUG
[Obsolete("use TarGZipHelper", true)]
public static class ZipHelper
{
[Obsolete("use TarGZipHelper.Create", true)]
public static void PackFiles(string filename, string directory)
{
TarGZipHelper.Create(filename, directory);
}
[Obsolete("use TarGZipHelper.Unpack", true)]
public static bool UnpackFiles(string file, string dir)
{
return TarGZipHelper.Unpack(file, dir);
}
}
[Obsolete("use TarGZipHelper", true)]
public static class ClassZip
{
[Obsolete("use TarGZipHelper.Create", true)]
public static bool Zip(string FileToZip, string ZipedFile, int level)
{
return TarGZipHelper.Create(FileToZip, ZipedFile, level);
}
[Obsolete("use TarGZipHelper.Unpack", true)]
public static void UnZip(string FileToUpZip, string ZipedFolder)
{
TarGZipHelper.Unpack(FileToUpZip, ZipedFolder);
}
}
#endif
}