近在做项目时用到了文件的批量压缩下载,使用了第三方的SharpZipLib包,后来想到了单个文件的压缩与解压,可能以后会用到相关技术,所以自己熟悉了一下并且借鉴了一些网上的相关代码,自己整理一下,这里我用到的是SharpZipLib 1.0.0版本,这里我新建一个控制台项目来展示。
一:创建项目并安装所需DLL
1、新建控制台项目ConsoleCompressApp
2、通过VisualStudio菜单中工具->NuGet包管理器->程序包管理控制台安装SharpZipLib包
命令是Install-Package SharpZipLib,如下图显示,已安装完成。
也可以通过鼠标选中项目然后右键弹出的菜单中选择管理NuGet程序包
选择第一个SharpZipLib包选择安装即可。
二:创建日志记录帮助类LogHelper
1 using System; 2 using System.IO; 3 4 namespace ConsoleCompressApp 5 { 6 public class LogHelper 7 { 8 private static readonly object __lockObject = new object(); 9 public static void Write(string message, string txtFileName = "") 10 { 11 try 12 { 13 if (string.IsNullOrWhiteSpace(txtFileName)) 14 { 15 txtFileName = AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + "log.txt"; 16 } 17 FileStream fs = null; 18 if (File.Exists(txtFileName)) 19 { 20 fs = new FileStream(txtFileName, FileMode.Append); 21 } 22 else 23 { 24 fs = new FileStream(txtFileName, FileMode.Create); 25 } 26 lock (__lockObject) 27 { 28 if (File.Exists(txtFileName) == false) 29 { 30 File.Create(txtFileName); 31 } 32 using (StreamWriter sw = new StreamWriter(fs)) 33 { 34 sw.Write("{0}:{1}", DateTime.Now.ToString("yyyy年MM月dd日 HH:mm:ss"), message + sw.NewLine); 35 } 36 } 37 38 } 39 catch (Exception) 40 { 41 throw; 42 } 43 } 44 } 45 }
三:创建压缩文件的帮助类SharpZipLibHelper
1、新建SharpZipLibHelper帮助类,并引用如下命名空间
1 using System; 2 using System.IO; 3 using ICSharpCode.SharpZipLib.Checksum; 4 using ICSharpCode.SharpZipLib.Zip; 5 6 namespace ConsoleCompressApp 7 { 8 public class SharpZipLibHelper 9 { 10 11 } 12 }
2、添加压缩单个文件的静态方法
1 ///2 /// 单个文件进行压缩 3 /// 4 /// 待压缩的文件(绝对路径) 5 /// 压缩后文件路径(绝对路径) 6 /// 压缩文件的名称(别名) 7 /// 压缩级别0-9,默认为5 8 /// 缓存大小,每次写入文件大小,默认为2048字节 9 /// 是否加密,默认加密 10 /// 加密的密码(为空的时候,不加密) 11 public static void CompressFile(string fileName, string compressedFilePath, string aliasFileName = "", int compressionLevel = 5, 12 int blockSize = 2048, bool isEncrypt = true, string encryptPassword = "") 13 { 14 if (File.Exists(fileName) == false) throw new FileNotFoundException("未能找到当前文件!", fileName); 15 try 16 { 17 string zipFileName = null; 18 ///获取待压缩文件名称(带后缀名) 19 string name = new FileInfo(fileName).Name; 20 zipFileName = compressedFilePath + Path.DirectorySeparatorChar + 21 (string.IsNullOrWhiteSpace(aliasFileName) ? name.Substring(0, name.LastIndexOf(".")) : aliasFileName) + ".zip"; 22 ///使用using语句,资源使用完毕,自动释放(类需继承IDispose接口) 23 using (FileStream fs = File.Create(zipFileName)) 24 { 25 using (ZipOutputStream outStream = new ZipOutputStream(fs)) 26 { 27 using (FileStream inStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) 28 { 29 ///zip文档的一个条目 30 ZipEntry entry = new ZipEntry(name); 31 ///压缩加密 32 if (isEncrypt) 33 { 34 outStream.Password = encryptPassword; 35 } 36 ///开始一个新的zip条目 37 outStream.PutNextEntry(entry); 38 ///设置压缩级别 39 outStream.SetLevel(compressionLevel); 40 ///缓冲区对象 41 byte[] buffer = new byte[blockSize]; 42 ///读入缓冲区的总字节数,执行到最后读取为0时,则读取完毕 43 int sizeRead = 0; 44 do 45 { 46 ///从流中读取字节,将该数据写入缓冲区 47 sizeRead = inStream.Read(buffer, 0, buffer.Length); 48 ///将给定的缓冲区的数据写入当前zip文档条目 49 outStream.Write(buffer, 0, sizeRead); 50 } 51 while (sizeRead > 0); 52 } 53 outStream.Finish(); 54 } 55 } 56 } 57 catch (System.Exception ex) 58 { 59 LogHelper.Write(ex.ToString()); 60 } 61 }
3、添加压缩文件目录的静态方法
1 ///2 /// 压缩文件夹 3 /// 4 /// 待压缩文件夹(绝对路径) 5 /// 压缩后的文件夹(绝对路径) 6 /// 压缩文件的名称(别名) 7 /// 是否加密,默认加密 8 /// 加密的密码(为空不进行加密) 9 public static void CompressDirectory(string directory, string compressedDirectory, string aliasFileName, bool isEncrypt, 10 string encryptPassword = "") 11 { 12 if (Directory.Exists(directory) == false) throw new DirectoryNotFoundException("未能找到当前路径!"); 13 try 14 { 15 string zipFileName = null; 16 ///获取待压缩文件名称 17 string name = new DirectoryInfo(directory).Name; 18 zipFileName = compressedDirectory + Path.DirectorySeparatorChar + 19 (string.IsNullOrWhiteSpace(aliasFileName) ? name : aliasFileName) + ".zip"; 20 21 ///使用using语句,资源使用完毕,自动释放(类需继承IDispose接口) 22 using (FileStream fs = File.Create(zipFileName)) 23 { 24 using (ZipOutputStream outStream = new ZipOutputStream(fs)) 25 { 26 if (isEncrypt) 27 { 28 ///压缩文件加密 29 outStream.Password = encryptPassword; 30 } 31 CompressTraversal(directory, outStream, ""); 32 outStream.Finish(); 33 } 34 } 35 } 36 catch (System.Exception ex) 37 { 38 LogHelper.Write(ex.ToString()); 39 } 40 } 41 42 /// 43 /// 压缩文件夹,并返回压缩后的文件数据流 44 /// 45 /// 待压缩文件夹(绝对路径) 46 /// 是否加密,默认加密 47 /// 加密的密码(为空不进行加密) 48 public static byte[] CompressDirectoryBytes(string directory, bool isEncrypt, string encryptPassword = "") 49 { 50 if (Directory.Exists(directory) == false) throw new DirectoryNotFoundException("未能找到当前路径!"); 51 try 52 { 53 ///获取待压缩文件名称 54 string name = new DirectoryInfo(directory).Name; 55 56 byte[] buffer = null; 57 58 MemoryStream ms = new MemoryStream(); 59 ZipOutputStream outStream = new ZipOutputStream(ms); 60 if (isEncrypt) 61 { 62 ///压缩文件加密 63 outStream.Password = encryptPassword; 64 } 65 CompressTraversal(directory, outStream, ""); 66 outStream.Finish(); 67 68 buffer = new byte[ms.Length]; 69 ms.Seek(0, SeekOrigin.Begin); 70 ms.Read(buffer, 0, (int)ms.Length); 71 return buffer; 72 } 73 catch (System.Exception ex) 74 { 75 LogHelper.Write(ex.ToString()); 76 return null; 77 } 78 } 79 80 /// 81 /// 递归遍历目录 82 /// 83 private static void CompressTraversal(string directory, ZipOutputStream outStream, string parentDirectory) 84 { 85 ///判断路径最后一个字符是否为当前系统的DirectorySeparatorChar 86 if (directory[directory.Length - 1] != Path.DirectorySeparatorChar) 87 { 88 directory += Path.DirectorySeparatorChar; 89 } 90 Crc32 crc = new Crc32(); 91 var fileOrDirectory = Directory.GetFileSystemEntries(directory); 92 ///遍历文件与目录 93 foreach (var item in fileOrDirectory) 94 { 95 ///判断是否为目录 96 if (Directory.Exists(item)) 97 { 98 CompressTraversal(item, outStream, (parentDirectory + item.Substring(item.LastIndexOf(Path.DirectorySeparatorChar) + 1) + Path.DirectorySeparatorChar)); 99 } 100 ///压缩文件 101 else 102 { 103 using (FileStream inStream = File.OpenRead(item)) 104 { 105 ///缓存区对象 106 byte[] buffer = new byte[inStream.Length]; 107 ///将流重置 108 inStream.Seek(0, SeekOrigin.Begin); 109 ///从文件流中读取字节,将该数据写入缓存区 110 inStream.Read(buffer, 0, (int)inStream.Length); 111 ///获取该文件名称(附带文件目录结构,例如git\\git.exe) 112 string fileName = parentDirectory + item.Substring(item.LastIndexOf(Path.DirectorySeparatorChar) + 1); 113 ///创建zip条目 114 ZipEntry entry = new ZipEntry(fileName); 115 entry.DateTime = DateTime.Now; 116 entry.Size = inStream.Length; 117 118 crc.Reset(); 119 crc.Update(buffer); 120 121 entry.Crc = crc.Value; 122 123 outStream.PutNextEntry(entry); 124 ///将缓存区对象数据写入流中 125 outStream.Write(buffer, 0, buffer.Length); 126 ///注意:一定要关闭当前条目,否则压缩包数据会丢失 127 outStream.CloseEntry(); 128 } 129 } 130 } 131 }
4、最后添加解压的静态方法
1 ///2 /// 解压缩 3 /// 4 /// 压缩文件(绝对路径) 5 /// 目标路径(绝对路径) 6 /// 加密密码 7 /// 是否覆盖 8 /// 缓存大小,每次写入文件大小,默认2048字节 9 public static void UnCompressFile(string compressedFile, string directory, string encryptPassword, bool overWrite = true, int blockSize = 2048) 10 { 11 if (File.Exists(compressedFile) == false) throw new FileNotFoundException("未能找到压缩文件!", compressedFile); 12 if (Directory.Exists(directory) == false) throw new DirectoryNotFoundException("未能找到目标路径!"); 13 14 ///判断路径最后一个字符是否为当前系统的DirectorySeparatorChar 15 if (directory[directory.Length - 1] != Path.DirectorySeparatorChar) 16 { 17 directory += Path.DirectorySeparatorChar; 18 } 19 try 20 { 21 ///使用using语句,资源使用完毕,自动释放(类需继承IDispose接口) 22 ///打开压缩文件进行读取 23 using (FileStream fs = File.OpenRead(compressedFile)) 24 { 25 ///创建压缩文件的输入流 26 using (ZipInputStream inStream = new ZipInputStream(fs)) 27 { 28 ///加密的密码 29 inStream.Password = encryptPassword; 30 ZipEntry entry; 31 while ((entry = inStream.GetNextEntry()) != null) 32 { 33 ///文件的父级目录名称 34 string directoryName = null; 35 ///文件的名称,例如git\\git.exe 36 string entryName = entry.Name; 37 38 if (string.IsNullOrWhiteSpace(entryName) == false) 39 { 40 directoryName = Path.GetDirectoryName(entryName) + Path.DirectorySeparatorChar; 41 } 42 ///获取文件名称,例如git.exe 43 string name = Path.GetFileName(entryName); 44 ///文件的父级目录的绝对路径 45 string newDirectory = directory + directoryName; 46 if (Directory.Exists(newDirectory) == false) 47 { 48 Directory.CreateDirectory(newDirectory); 49 } 50 51 if (string.IsNullOrWhiteSpace(name) == false) 52 { 53 ///文件的绝对路径 54 string fileName = directory + directoryName + name; 55 ///如果覆盖解压或者本地不存在当前文件则进行解压缩 56 if (overWrite || File.Exists(fileName) == false) 57 { 58 using (FileStream fsWrite = File.Create(fileName)) 59 { 60 ///缓存区对象 61 byte[] buffer = new byte[blockSize]; 62 ///读取的字节数 63 int sizeRead = 0; 64 ///读取完成,解压完成 65 do 66 { 67 ///从流中读取字节,将此数据写入缓存区 68 sizeRead = inStream.Read(buffer, 0, buffer.Length); 69 ///将字节写入文件流 70 fsWrite.Write(buffer, 0, buffer.Length); 71 } while (sizeRead > 0); 72 } 73 } 74 } 75 } 76 } 77 } 78 } 79 catch (Exception ex) 80 { 81 LogHelper.Write(ex.ToString()); 82 } 83 }
四:在Program类Main方法中调用方法
1、新建几个文件目录用来测试,目录结构如下图
2、编写代码,进行压缩与解压测试,如下
1 using System; 2 using System.IO; 3 4 namespace ConsoleCompressApp 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 var projectDirectory = Path.GetFullPath("../.."); 11 var directorySeparatorChar = Path.DirectorySeparatorChar; 12 Console.WriteLine("您要压缩Files\\Packages\\git.exe文件么?"); 13 if (Console.ReadLine().Trim().ToLower()=="yes") 14 { 15 SharpZipLibHelper.CompressFile( 16 fileName: projectDirectory + directorySeparatorChar + "Files" + directorySeparatorChar + 17 "Packages" + directorySeparatorChar + "git.exe", 18 compressedFilePath: projectDirectory + directorySeparatorChar + "ZipFiles", 19 aliasFileName: "", 20 compressionLevel: 8, 21 blockSize: 2048, 22 isEncrypt: true, 23 encryptPassword: "123"); 24 } 25 Console.WriteLine("您要压缩Files整个目录么?"); 26 if (Console.ReadLine().Trim().ToLower() == "yes") 27 { 28 SharpZipLibHelper.CompressDirectory( 29 directory: projectDirectory + directorySeparatorChar + "Files", 30 compressedDirectory: projectDirectory + directorySeparatorChar + "ZipDirectory", 31 aliasFileName: "Files", 32 isEncrypt: true, 33 encryptPassword: "456"); 34 } 35 Console.WriteLine("您要将ZipDirectory中的Files.zip解压缩到UnZipFiles目录中么?"); 36 if (Console.ReadLine().Trim().ToLower() == "yes") 37 { 38 SharpZipLibHelper.UnCompressFile(compressedFile: projectDirectory + directorySeparatorChar + 39 "ZipDirectory" + directorySeparatorChar + "Files.zip", 40 directory: projectDirectory + directorySeparatorChar + "UnZipFiles", 41 encryptPassword: "456"); 42 } 43 Console.WriteLine("恭喜您,操作完成了!"); 44 Console.ReadLine(); 45 } 46 } 47 }
3、点击启动,进行测试,结果如下:
文件目录如下