本文介紹壓縮庫SharpZipLib的使用,提供封裝類的源代碼,以及測試UI的源代碼。 ...
SharpZipLib是一個開源的C#壓縮解壓庫,應用非常廣泛。就像用ADO.NET操作資料庫要打開連接、執行命令、關閉連接等多個步驟一樣,用SharpZipLib進行壓縮和解壓也需要多個步驟。除了初學者會用原始的方法做一步一步完成,實際開發的時候都會進行更易用的封裝。這裡分享我對SharpZipLib的封裝,支持對文件和位元組進行壓縮和解壓操作,支持多個文件和文件夾壓縮,支持設置備註和密碼。(文章源網址:http://www.cnblogs.com/conexpress/p/SharpZipClass.html) SharpZipLib的官方地址是:http://icsharpcode.github.io/SharpZipLib/,實際使用可以通過NuGet獲取,在NuGetd地址是:http://www.nuget.org/packages/SharpZipLib/ 在Visual Studio中可以通過NuGet程式包管理控制台輸入命令PM> Install-Package SharpZipLib或者用NuGet管理界面搜索並安裝。 我把使用SharpZipLib的方法卸載一個類裡面,作為靜態方法調用,免去創建類的麻煩。其中核心壓縮和解壓文件的方法代碼如下:
1 /// <summary> 2 /// 壓縮多個文件/文件夾 3 /// </summary> 4 /// <param name="sourceList">源文件/文件夾路徑列表</param> 5 /// <param name="zipFilePath">壓縮文件路徑</param> 6 /// <param name="comment">註釋信息</param> 7 /// <param name="password">壓縮密碼</param> 8 /// <param name="compressionLevel">壓縮等級,範圍從0到9,可選,預設為6</param> 9 /// <returns></returns> 10 public static bool CompressFile(IEnumerable<string> sourceList, string zipFilePath, 11 string comment = null, string password = null, int compressionLevel = 6) 12 { 13 bool result = false; 14 15 try 16 { 17 //檢測目標文件所屬的文件夾是否存在,如果不存在則建立 18 string zipFileDirectory = Path.GetDirectoryName(zipFilePath); 19 if (!Directory.Exists(zipFileDirectory)) 20 { 21 Directory.CreateDirectory(zipFileDirectory); 22 } 23 24 Dictionary<string, string> dictionaryList = PrepareFileSystementities(sourceList); 25 26 using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipFilePath))) 27 { 28 zipStream.Password = password;//設置密碼 29 zipStream.SetComment(comment);//添加註釋 30 zipStream.SetLevel(CheckCompressionLevel(compressionLevel));//設置壓縮等級 31 32 foreach (string key in dictionaryList.Keys)//從字典取文件添加到壓縮文件 33 { 34 if (File.Exists(key))//判斷是文件還是文件夾 35 { 36 FileInfo fileItem = new FileInfo(key); 37 38 using (FileStream readStream = fileItem.Open(FileMode.Open, 39 FileAccess.Read, FileShare.Read)) 40 { 41 ZipEntry zipEntry = new ZipEntry(dictionaryList[key]); 42 zipEntry.DateTime = fileItem.LastWriteTime; 43 zipEntry.Size = readStream.Length; 44 zipStream.PutNextEntry(zipEntry); 45 int readLength = 0; 46 byte[] buffer = new byte[BufferSize]; 47 48 do 49 { 50 readLength = readStream.Read(buffer, 0, BufferSize); 51 zipStream.Write(buffer, 0, readLength); 52 } while (readLength == BufferSize); 53 54 readStream.Close(); 55 } 56 } 57 else//對文件夾的處理 58 { 59 ZipEntry zipEntry = new ZipEntry(dictionaryList[key] + "/"); 60 zipStream.PutNextEntry(zipEntry); 61 } 62 } 63 64 zipStream.Flush(); 65 zipStream.Finish(); 66 zipStream.Close(); 67 } 68 69 result = true; 70 } 71 catch (System.Exception ex) 72 { 73 throw new Exception("壓縮文件失敗", ex); 74 } 75 76 return result; 77 } 78 79 /// <summary> 80 /// 解壓文件到指定文件夾 81 /// </summary> 82 /// <param name="sourceFile">壓縮文件</param> 83 /// <param name="destinationDirectory">目標文件夾,如果為空則解壓到當前文件夾下</param> 84 /// <param name="password">密碼</param> 85 /// <returns></returns> 86 public static bool DecomparessFile(string sourceFile, string destinationDirectory = null, string password = null) 87 { 88 bool result = false; 89 90 if (!File.Exists(sourceFile)) 91 { 92 throw new FileNotFoundException("要解壓的文件不存在", sourceFile); 93 } 94 95 if (string.IsNullOrWhiteSpace(destinationDirectory)) 96 { 97 destinationDirectory = Path.GetDirectoryName(sourceFile); 98 } 99 100 try 101 { 102 if (!Directory.Exists(destinationDirectory)) 103 { 104 Directory.CreateDirectory(destinationDirectory); 105 } 106 107 using (ZipInputStream zipStream = new ZipInputStream(File.Open(sourceFile, FileMode.Open, 108 FileAccess.Read, FileShare.Read))) 109 { 110 zipStream.Password = password; 111 ZipEntry zipEntry = zipStream.GetNextEntry(); 112 113 while (zipEntry != null) 114 { 115 if (zipEntry.IsDirectory)//如果是文件夾則創建 116 { 117 Directory.CreateDirectory(Path.Combine(destinationDirectory, 118 Path.GetDirectoryName(zipEntry.Name))); 119 } 120 else 121 { 122 string fileName = Path.GetFileName(zipEntry.Name); 123 if (!string.IsNullOrEmpty(fileName) && fileName.Trim().Length > 0) 124 { 125 FileInfo fileItem = new FileInfo(Path.Combine(destinationDirectory, zipEntry.Name)); 126 using (FileStream writeStream = fileItem.Create()) 127 { 128 byte[] buffer = new byte[BufferSize]; 129 int readLength = 0; 130 131 do 132 { 133 readLength = zipStream.Read(buffer, 0, BufferSize); 134 writeStream.Write(buffer, 0, readLength); 135 } while (readLength == BufferSize); 136 137 writeStream.Flush(); 138 writeStream.Close(); 139 } 140 fileItem.LastWriteTime = zipEntry.DateTime; 141 } 142 } 143 zipEntry = zipStream.GetNextEntry();//獲取下一個文件 144 } 145 146 zipStream.Close(); 147 } 148 result = true; 149 } 150 catch (System.Exception ex) 151 { 152 throw new Exception("文件解壓發生錯誤", ex); 153 } 154 155 return result; 156 }壓縮方法CompressFile中sourceList是路徑數組,支持文件夾和文件的路徑。當遇到文件夾時會自動將下級文件和文件夾包含,並會檢測重覆項。文件路徑處理的方法如下:
1 /// <summary> 2 /// 為壓縮準備文件系統對象 3 /// </summary> 4 /// <param name="sourceFileEntityPathList"></param> 5 /// <returns></returns> 6 private static Dictionary<string, string> PrepareFileSystementities(IEnumerable<string> sourceFileEntityPathList) 7 { 8 Dictionary<string, string> fileEntityDictionary = new Dictionary<string, string>();//文件字典 9 string parentDirectoryPath = ""; 10 foreach (string fileEntityPath in sourceFileEntityPathList) 11 { 12 string path = fileEntityPath; 13 //保證傳入的文件夾也被壓縮進文件 14 if (path.EndsWith(@"\")) 15 { 16 path = path.Remove(path.LastIndexOf(@"\")); 17 } 18 19 parentDirectoryPath = Path.GetDirectoryName(path) + @"\"; 20 21 if (parentDirectoryPath.EndsWith(@":\\"))//防止根目錄下把盤符壓入的錯誤 22 { 23 parentDirectoryPath = parentDirectoryPath.Replace(@"\\", @"\"); 24 } 25 26 //獲取目錄中所有的文件系統對象 27 Dictionary<string, string> subDictionary = GetAllFileSystemEntities(path, parentDirectoryPath); 28 29 //將文件系統對象添加到總的文件字典中 30 foreach (string key in subDictionary.Keys) 31 { 32 if (!fileEntityDictionary.ContainsKey(key))//檢測重覆項 33 { 34 fileEntityDictionary.Add(key, subDictionary[key]); 35 } 36 } 37 } 38 return fileEntityDictionary; 39 } 40 41 /// <summary> 42 /// 獲取所有文件系統對象 43 /// </summary> 44 /// <param name="source">源路徑</param> 45 /// <param name="topDirectory">頂級文件夾</param> 46 /// <returns>字典中Key為完整路徑,Value為文件(夾)名稱</returns> 47 private static Dictionary<string, string> GetAllFileSystemEntities(string source, string topDirectory) 48 { 49 Dictionary<string, string> entitiesDictionary = new Dictionary<string, string>(); 50 entitiesDictionary.Add(source, source.Replace(topDirectory, "")); 51 52 if (Directory.Exists(source)) 53 { 54 //一次性獲取下級所有目錄,避免遞歸 55 string[] directories = Directory.GetDirectories(source, "*.*", SearchOption.AllDirectories); 56 foreach (string directory in directories) 57 { 58 entitiesDictionary.Add(directory, directory.Replace(topDirectory, "")); 59 } 60 61 string[] files = Directory.GetFiles(source, "*.*", SearchOption.AllDirectories); 62 foreach (string file in files) 63 { 64 entitiesDictionary.Add(file, file.Replace(topDirectory, "")); 65 } 66 } 67 68 return entitiesDictionary; 69 }
除了支持文件和文件夾壓縮解壓,還提供了對位元組的壓縮解壓方法:
1 /// <summary> 2 /// 壓縮位元組數組 3 /// </summary> 4 /// <param name="sourceBytes">源位元組數組</param> 5 /// <param name="compressionLevel">壓縮等級</param> 6 /// <param name="password">密碼</param> 7 /// <returns>壓縮後的位元組數組</returns> 8 public static byte[] CompressBytes(byte[] sourceBytes, string password = null, int compressionLevel = 6) 9 { 10 byte[] result = new byte[] { }; 11 12 if (sourceBytes.Length > 0) 13 { 14 try 15 { 16 using (MemoryStream tempStream = new MemoryStream()) 17 { 18 using (MemoryStream readStream = new MemoryStream(sourceBytes)) 19 { 20 using (ZipOutputStream zipStream = new ZipOutputStream(tempStream)) 21 { 22 zipStream.Password = password;//設置密碼 23 zipStream.SetLevel(CheckCompressionLevel(compressionLevel));//設置壓縮等級 24 25 ZipEntry zipEntry = new ZipEntry("ZipBytes"); 26 zipEntry.DateTime = DateTime.Now; 27 zipEntry.Size = sourceBytes.Length; 28 zipStream.PutNextEntry(zipEntry); 29 int readLength = 0; 30 byte[] buffer = new byte[BufferSize]; 31 32 do 33 { 34 readLength = readStream.Read(buffer, 0, BufferSize); 35 zipStream.Write(buffer, 0, readLength); 36 } while (readLength == BufferSize); 37 38 readStream.Close(); 39 zipStream.Flush(); 40 zipStream.Finish(); 41 result = tempStream.ToArray(); 42 zipStream.Close(); 43 } 44 } 45 } 46 } 47 catch (System.Exception ex) 48 { 49 throw new Exception("壓縮位元組數組發生錯誤", ex); 50 } 51 } 52 53 return result; 54 } 55 56 /// <summary> 57 /// 解壓位元組數組 58 /// </summary> 59 /// <param name="sourceBytes">源位元組數組</param> 60 /// <param name="password">密碼</param> 61 /// <returns>解壓後的位元組數組</returns> 62 public static byte[] DecompressBytes(byte[] sourceBytes, string password = null) 63 { 64 byte[] result = new byte[] { }; 65 66 if (sourceBytes.Length > 0) 67 { 68 try 69 { 70 using (MemoryStream tempStream = new MemoryStream(sourceBytes)) 71 { 72 using (MemoryStream writeStream = new MemoryStream()) 73 { 74 using (ZipInputStream zipStream = new ZipInputStream(tempStream)) 75 { 76 zipStream.Password = password; 77 ZipEntry zipEntry = zipStream.GetNextEntry(); 78 79 if (zipEntry != null) 80 { 81 byte[] buffer = new byte[BufferSize]; 82 int readLength = 0; 83 84 do 85 { 86 readLength = zipStream.Read(buffer, 0, BufferSize); 87 writeStream.Write(buffer, 0, readLength); 88 } while (readLength == BufferSize); 89 90 writeStream.Flush(); 91 result = writeStream.ToArray(); 92 writeStream.Close(); 93 } 94 zipStream.Close(); 95 } 96 } 97 } 98 } 99 catch (System.Exception ex) 100 { 101 throw new Exception("解壓位元組數組發生錯誤", ex); 102 } 103 } 104 return result; 105 }View Code
為了測試該類,我寫了一個WinForm程式,界面如下:
可以將文件和文件夾拖放到壓縮列表中,選中壓縮列表中的對象可以按Delete鍵進行刪除。文件解壓區域也可以將要解壓的文件拖放到文件路徑輸入文本框。實際測試可以正確壓縮和解壓,包括設置密碼,壓縮和解壓操作和WinRAR完全相容。如果您在代碼中發現問題或有可以優化完善的地方,歡迎指出,謝謝! 程式源代碼下載:http://files.cnblogs.com/files/conexpress/SharpZipTest.zip 參考資料: http://www.cnblogs.com/kissdodog/p/3525295.html http://www.cnblogs.com/xuanye/archive/2011/10/19/2217211.html