近在做項目時用到了文件的批量壓縮下載,使用了第三方的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 /// <summary> 2 /// 單個文件進行壓縮 3 /// </summary> 4 /// <param name="fileName">待壓縮的文件(絕對路徑)</param> 5 /// <param name="compressedFilePath">壓縮后文件路徑(絕對路徑)</param> 6 /// <param name="aliasFileName">壓縮文件的名稱(別名)</param> 7 /// <param name="compressionLevel">壓縮級別0-9,默認為5</param> 8 /// <param name="blockSize">緩存大小,每次寫入文件大小,默認為2048字節</param> 9 /// <param name="isEncrypt">是否加密,默認加密</param> 10 /// <param name="encryptPassword">加密的密碼(為空的時候,不加密)</param> 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 /// <summary> 2 /// 壓縮文件夾 3 /// </summary> 4 /// <param name="directory">待壓縮文件夾(絕對路徑)</param> 5 /// <param name="compressedDirectory">壓縮后的文件夾(絕對路徑)</param> 6 /// <param name="aliasFileName">壓縮文件的名稱(別名)</param> 7 /// <param name="isEncrypt">是否加密,默認加密</param> 8 /// <param name="encryptPassword">加密的密碼(為空不進行加密)</param> 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 /// <summary> 43 /// 壓縮文件夾,並返回壓縮后的文件數據流 44 /// </summary> 45 /// <param name="directory">待壓縮文件夾(絕對路徑)</param> 46 /// <param name="isEncrypt">是否加密,默認加密</param> 47 /// <param name="encryptPassword">加密的密碼(為空不進行加密)</param> 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 /// <summary> 81 /// 遞歸遍歷目錄 82 /// </summary> 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 /// <summary> 2 /// 解壓縮 3 /// </summary> 4 /// <param name="compressedFile">壓縮文件(絕對路徑)</param> 5 /// <param name="directory">目標路徑(絕對路徑)</param> 6 /// <param name="encryptPassword">加密密碼</param> 7 /// <param name="overWrite">是否覆蓋</param> 8 /// <param name="blockSize">緩存大小,每次寫入文件大小,默認2048字節</param> 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、點擊啟動,進行測試,結果如下:
文件目錄如下