using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.Tar; using ICSharpCode.SharpZipLib.Zip.Compression; using System.IO; using System.Text; using System.Threading.Tasks; namespace System.Application { public static class TarGZipHelper { /// /// 创建压缩包文件 /// /// 要创建的文件路径 /// 要打包的目录 /// 压缩等级,取值范围在 ~ /// 进度消息监听 /// 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, Encoding.UTF8); 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); archive.WriteEntry(entry, false); } } void HandleDirs(string dirPath_) { foreach (var dir in Directory.GetDirectories(dirPath_)) { HandleFiles(dir); } } return true; } /// /// 解压压缩包文件 /// /// 要解压的压缩包文件路径 /// 要解压的文件夹路径,文件夹必须不存在 /// 进度消息监听 /// 进度值监听 /// public static bool Unpack(string filePath, string dirPath, ProgressMessageHandler? progressMessage = null, IProgress? progress = null) { 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; async void ProgressMonitor() { while (!isFinish) { var value = fs.Position / length; progress.Report(value); await Task.Delay(200); } } Directory.CreateDirectory(dirPath); using var s = new GZipInputStream(fs); using var archive = TarArchive.CreateInputTarArchive(s, Encoding.UTF8); if (progressMessage != null) archive.ProgressMessageEvent += progressMessage; if (progress != null) Task.Factory.StartNew(ProgressMonitor); archive.ExtractContents(dirPath); isFinish = true; progress?.Report(1f); 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 }