前面介紹了六種.NET組件,其中有一種組件是寫文件的壓縮和解壓,現(xiàn)在介紹另一種文件的解壓縮組件SharpZipLib。在這個組件介紹系列中,只為簡單的介紹組件的背景和簡單的應(yīng)用,讀者在閱讀時可以結(jié)合官網(wǎng)的相關(guān)介紹和在本地實際操作。
相關(guān)的組件功能非常強大,在筆者的介紹中只是提及到簡單的應(yīng)用,需要了解更多的操作和特性,可以根據(jù)官網(wǎng)介紹,或者查看DLL文件的相關(guān)類和方法,以此來擴展相關(guān)的業(yè)務(wù)需要。
SharpZipLib是一個完全在C#中為.NET平臺編寫的Zip,GZip,Tar和BZip2庫。
一.SharpZipLib組件概述:
ziplib(SharpZipLib,以前的NZipLib)是一個完全在C#為.NET平臺編寫的Zip,GZip,Tar和BZip2庫。它實現(xiàn)為一個程序集(可安裝在GAC中),因此可以輕松地集成到其他項目(任何.NET語言)中。 #ziplib的創(chuàng)建者這樣說:“我已經(jīng)將zip庫移植到C#,因為我需要gzip / zip壓縮,我不想使用libzip.dll或類似的東西我想要的所有在純C#“。
SharpZipLib官網(wǎng)提供的下載操作:.NET 1.1,.NET 2.0(3.5,4.0),.NET CF 1.0,.NET CF 2.0的裝配:下載237 KB,源代碼和示例下載708 KB;源代碼和示例下載708 KB;幫助文件下載1208 KB;
SharpZipLib是在GPL下發(fā)布,遵守開源協(xié)議。
二.SharpZipLib核心類和方法介紹:
以上簡單的介紹了SharpZipLib組件的相關(guān)背景,現(xiàn)在具體看一下該組件的相關(guān)核心類和方法:
1.ZipOutputStream類PutNextEntry():
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
public void PutNextEntry(ZipEntry entry) { bool hasCrc; if (entry == null ) { throw new ArgumentNullException( "entry" ); } if ( this .entries == null ) { throw new InvalidOperationException( "ZipOutputStream was finished" ); } if ( this .curEntry != null ) { this .CloseEntry(); } if ( this .entries.Count == 0x7fffffff) { throw new ZipException( "Too many entries for Zip file" ); } CompressionMethod compressionMethod = entry.CompressionMethod; int defaultCompressionLevel = this .defaultCompressionLevel; entry.Flags &= 0x800; this .patchEntryHeader = false ; if (entry.Size == 0L) { entry.CompressedSize = entry.Size; entry.Crc = 0L; compressionMethod = CompressionMethod.Stored; hasCrc = true ; } else { hasCrc = (entry.Size >= 0L) && entry.HasCrc; if (compressionMethod == CompressionMethod.Stored) { if (!hasCrc) { if (! base .CanPatchEntries) { compressionMethod = CompressionMethod.Deflated; defaultCompressionLevel = 0; } } else { entry.CompressedSize = entry.Size; hasCrc = entry.HasCrc; } } } if (!hasCrc) { if (! base .CanPatchEntries) { entry.Flags |= 8; } else { this .patchEntryHeader = true ; } } if ( base .Password != null ) { entry.IsCrypted = true ; if (entry.Crc < 0L) { entry.Flags |= 8; } } entry.Offset = this .offset; entry.CompressionMethod = compressionMethod; this .curMethod = compressionMethod; this .sizePatchPos = -1L; if (( this .useZip64_ == UseZip64.On) || ((entry.Size < 0L) && ( this .useZip64_ == UseZip64.Dynamic))) { entry.ForceZip64(); } this .WriteLeInt(0x4034b50); this .WriteLeShort(entry.Version); this .WriteLeShort(entry.Flags); this .WriteLeShort(( byte ) entry.CompressionMethodForHeader); this .WriteLeInt(( int ) entry.DosTime); if (hasCrc) { this .WriteLeInt(( int ) entry.Crc); if (entry.LocalHeaderRequiresZip64) { this .WriteLeInt(-1); this .WriteLeInt(-1); } else { this .WriteLeInt(entry.IsCrypted ? ((( int ) entry.CompressedSize) + 12) : (( int ) entry.CompressedSize)); this .WriteLeInt(( int ) entry.Size); } } else { if ( this .patchEntryHeader) { this .crcPatchPos = base .baseOutputStream_.Position; } this .WriteLeInt(0); if ( this .patchEntryHeader) { this .sizePatchPos = base .baseOutputStream_.Position; } if (entry.LocalHeaderRequiresZip64 || this .patchEntryHeader) { this .WriteLeInt(-1); this .WriteLeInt(-1); } else { this .WriteLeInt(0); this .WriteLeInt(0); } } byte [] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name); if (buffer.Length > 0xffff) { throw new ZipException( "Entry name too long." ); } ZipExtraData extraData = new ZipExtraData(entry.ExtraData); if (entry.LocalHeaderRequiresZip64) { extraData.StartNewEntry(); if (hasCrc) { extraData.AddLeLong(entry.Size); extraData.AddLeLong(entry.CompressedSize); } else { extraData.AddLeLong(-1L); extraData.AddLeLong(-1L); } extraData.AddNewEntry(1); if (!extraData.Find(1)) { throw new ZipException( "Internal error cant find extra data" ); } if ( this .patchEntryHeader) { this .sizePatchPos = extraData.CurrentReadIndex; } } else { extraData.Delete(1); } if (entry.AESKeySize > 0) { AddExtraDataAES(entry, extraData); } byte [] entryData = extraData.GetEntryData(); this .WriteLeShort(buffer.Length); this .WriteLeShort(entryData.Length); if (buffer.Length > 0) { base .baseOutputStream_.Write(buffer, 0, buffer.Length); } if (entry.LocalHeaderRequiresZip64 && this .patchEntryHeader) { this .sizePatchPos += base .baseOutputStream_.Position; } if (entryData.Length > 0) { base .baseOutputStream_.Write(entryData, 0, entryData.Length); } this .offset += (30 + buffer.Length) + entryData.Length; if (entry.AESKeySize > 0) { this .offset += entry.AESOverheadSize; } this .curEntry = entry; this .crc.Reset(); if (compressionMethod == CompressionMethod.Deflated) { base .deflater_.Reset(); base .deflater_.SetLevel(defaultCompressionLevel); } this .size = 0L; if (entry.IsCrypted) { if (entry.AESKeySize > 0) { this .WriteAESHeader(entry); } else if (entry.Crc < 0L) { this .WriteEncryptionHeader(entry.DosTime << 0x10); } else { this .WriteEncryptionHeader(entry.Crc); } } } |
2.ZipOutputStream類Finish():
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
|
public override void Finish() { if ( this .entries != null ) { if ( this .curEntry != null ) { this .CloseEntry(); } long count = this .entries.Count; long sizeEntries = 0L; foreach (ZipEntry entry in this .entries) { this .WriteLeInt(0x2014b50); this .WriteLeShort(0x33); this .WriteLeShort(entry.Version); this .WriteLeShort(entry.Flags); this .WriteLeShort(( short ) entry.CompressionMethodForHeader); this .WriteLeInt(( int ) entry.DosTime); this .WriteLeInt(( int ) entry.Crc); if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL)) { this .WriteLeInt(-1); } else { this .WriteLeInt(( int ) entry.CompressedSize); } if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL)) { this .WriteLeInt(-1); } else { this .WriteLeInt(( int ) entry.Size); } byte [] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name); if (buffer.Length > 0xffff) { throw new ZipException( "Name too long." ); } ZipExtraData extraData = new ZipExtraData(entry.ExtraData); if (entry.CentralHeaderRequiresZip64) { extraData.StartNewEntry(); if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL)) { extraData.AddLeLong(entry.Size); } if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL)) { extraData.AddLeLong(entry.CompressedSize); } if (entry.Offset >= 0xffffffffL) { extraData.AddLeLong(entry.Offset); } extraData.AddNewEntry(1); } else { extraData.Delete(1); } if (entry.AESKeySize > 0) { AddExtraDataAES(entry, extraData); } byte [] entryData = extraData.GetEntryData(); byte [] buffer3 = (entry.Comment != null ) ? ZipConstants.ConvertToArray(entry.Flags, entry.Comment) : new byte [0]; if (buffer3.Length > 0xffff) { throw new ZipException( "Comment too long." ); } this .WriteLeShort(buffer.Length); this .WriteLeShort(entryData.Length); this .WriteLeShort(buffer3.Length); this .WriteLeShort(0); this .WriteLeShort(0); if (entry.ExternalFileAttributes != -1) { this .WriteLeInt(entry.ExternalFileAttributes); } else if (entry.IsDirectory) { this .WriteLeInt(0x10); } else { this .WriteLeInt(0); } if (entry.Offset >= 0xffffffffL) { this .WriteLeInt(-1); } else { this .WriteLeInt(( int ) entry.Offset); } if (buffer.Length > 0) { base .baseOutputStream_.Write(buffer, 0, buffer.Length); } if (entryData.Length > 0) { base .baseOutputStream_.Write(entryData, 0, entryData.Length); } if (buffer3.Length > 0) { base .baseOutputStream_.Write(buffer3, 0, buffer3.Length); } sizeEntries += ((0x2e + buffer.Length) + entryData.Length) + buffer3.Length; } using (ZipHelperStream stream = new ZipHelperStream( base .baseOutputStream_)) { stream.WriteEndOfCentralDirectory(count, sizeEntries, this .offset, this .zipComment); } this .entries = null ; } } |
3.ZipEntry類Clone():
1
2
3
4
5
6
7
8
9
10
|
public object Clone() { ZipEntry entry = (ZipEntry) base .MemberwiseClone(); if ( this .extra != null ) { entry.extra = new byte [ this .extra.Length]; Array.Copy( this .extra, 0, entry.extra, 0, this .extra.Length); } return entry; } |
4.ZipOutputStream類Write():
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
|
public override void Write( byte [] buffer, int offset, int count) { if ( this .curEntry == null ) { throw new InvalidOperationException( "No open entry." ); } if (buffer == null ) { throw new ArgumentNullException( "buffer" ); } if (offset < 0) { throw new ArgumentOutOfRangeException( "offset" , "Cannot be negative" ); } if (count < 0) { throw new ArgumentOutOfRangeException( "count" , "Cannot be negative" ); } if ((buffer.Length - offset) < count) { throw new ArgumentException( "Invalid offset/count combination" ); } this .crc.Update(buffer, offset, count); this .size += count; switch ( this .curMethod) { case CompressionMethod.Stored: if ( base .Password != null ) { this .CopyAndEncrypt(buffer, offset, count); } else { base .baseOutputStream_.Write(buffer, offset, count); } break ; case CompressionMethod.Deflated: base .Write(buffer, offset, count); break ; } } |
三.SharpZipLib實例:
1.壓縮單個文件:
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
|
/// <summary> /// 壓縮單個文件 /// </summary> /// <param name="fileToZip">要壓縮的文件</param> /// <param name="zipedFile">壓縮后的文件</param> /// <param name="compressionLevel">壓縮等級</param> /// <param name="blockSize">每次寫入大小</param> public static void ZipFile( string fileToZip, string zipedFile, int compressionLevel, int blockSize) { if ( string .IsNullOrEmpty(fileToZip)) { throw new ArgumentNullException(fileToZip); } if ( string .IsNullOrEmpty(zipedFile)) { throw new ArgumentNullException(zipedFile); } if (!File.Exists(fileToZip)) { throw new FileNotFoundException( "指定要壓縮的文件: " + fileToZip + " 不存在!" ); } try { using (var zipFile = File.Create(zipedFile)) { using (var zipStream = new ZipOutputStream(zipFile)) { using (var streamToZip = new FileStream(fileToZip, FileMode.Open, FileAccess.Read)) { var fileName = fileToZip.Substring(fileToZip.LastIndexOf( "\\" , StringComparison.Ordinal) + 1); var zipEntry = new ZipEntry(fileName); zipStream.PutNextEntry(zipEntry); zipStream.SetLevel(compressionLevel); var buffer = new byte [blockSize]; try { int sizeRead; do { sizeRead = streamToZip.Read(buffer, 0, buffer.Length); zipStream.Write(buffer, 0, sizeRead); } while (sizeRead > 0); } catch (Exception ex) { throw new Exception(ex.Message); } streamToZip.Close(); } zipStream.Finish(); zipStream.Close(); } zipFile.Close(); } } catch (IOException ioex) { throw new IOException(ioex.Message); } catch (Exception ex) { throw new Exception(ex.Message); } } |
2. 壓縮單個文件:
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
|
/// <summary> /// 壓縮單個文件 /// </summary> /// <param name="fileToZip">要進(jìn)行壓縮的文件名</param> /// <param name="zipedFile">壓縮后生成的壓縮文件名</param> public static void ZipFile( string fileToZip, string zipedFile) { if ( string .IsNullOrEmpty(fileToZip)) { throw new ArgumentException(fileToZip); } if ( string .IsNullOrEmpty(zipedFile)) { throw new ArgumentException(zipedFile); } if (!File.Exists(fileToZip)) { throw new FileNotFoundException( "指定要壓縮的文件: " + fileToZip + " 不存在!" ); } try { using (var fs = File.OpenRead(fileToZip)) { var buffer = new byte [fs.Length]; fs.Read(buffer, 0, buffer.Length); fs.Close(); using (var zipFile = File.Create(zipedFile)) { using (var zipStream = new ZipOutputStream(zipFile)) { var fileName = fileToZip.Substring(fileToZip.LastIndexOf( "\\" , StringComparison.Ordinal) + 1); var zipEntry = new ZipEntry(fileName); zipStream.PutNextEntry(zipEntry); zipStream.SetLevel(5); zipStream.Write(buffer, 0, buffer.Length); zipStream.Finish(); zipStream.Close(); } } } } catch (IOException ioex) { throw new IOException(ioex.Message); } catch (Exception ex) { throw new Exception(ex.Message); } } |
3.壓縮多層目錄:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/// <summary> /// 壓縮多層目錄 /// </summary> /// <param name="strDirectory">目錄</param> /// <param name="zipedFile">壓縮文件</param> public static void ZipFileDirectory( string strDirectory, string zipedFile) { if ( string .IsNullOrEmpty(strDirectory)) { throw new ArgumentException(strDirectory); } if ( string .IsNullOrEmpty(zipedFile)) { throw new ArgumentException(zipedFile); } using (var zipFile = File.Create(zipedFile)) { using (var s = new ZipOutputStream(zipFile)) { ZipSetp(strDirectory, s, "" ); } } } |
4.遞歸遍歷目錄:
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
|
/// <summary> /// 遞歸遍歷目錄 /// </summary> /// <param name="strDirectory">目錄</param> /// <param name="s">ZipOutputStream對象</param> /// <param name="parentPath">父路徑</param> private static void ZipSetp(string strDirectory, ZipOutputStream s, string parentPath) { if (strDirectory[strDirectory.Length - 1 ] != Path.DirectorySeparatorChar) { strDirectory += Path.DirectorySeparatorChar; } var crc = new Crc32(); var filenames = Directory.GetFileSystemEntries(strDirectory); try { // 遍歷所有的文件和目錄 foreach (var file in filenames) { // 先當(dāng)作目錄處理如果存在這個目錄就遞歸Copy該目錄下面的文件 if (Directory.Exists(file)) { var pPath = parentPath; pPath += file.Substring(file.LastIndexOf( "\\" , StringComparison.Ordinal) + 1 ); pPath += "\\" ; ZipSetp(file, s, pPath); } // 否則直接壓縮文件 else { //打開壓縮文件 using (var fs = File.OpenRead(file)) { var buffer = new byte [fs.Length]; fs.Read(buffer, 0 , buffer.Length); var fileName = parentPath + file.Substring(file.LastIndexOf( "\\" , StringComparison.Ordinal) + 1 ); var entry = new ZipEntry(fileName) { DateTime = DateTime.Now, Size = fs.Length }; fs.Close(); crc.Reset(); crc.Update(buffer); entry.Crc = crc.Value; s.PutNextEntry(entry); s.Write(buffer, 0 , buffer.Length); } } } } catch (IOException ioex) { throw new IOException(ioex.Message); } catch (Exception ex) { throw new Exception(ex.Message); } } |
5.解壓縮一個 zip 文件:
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
|
/// <summary> /// 解壓縮一個 zip 文件。 /// </summary> /// <param name="zipedFile">The ziped file.</param> /// <param name="strDirectory">The STR directory.</param> /// <param name="password">zip 文件的密碼。</param> /// <param name="overWrite">是否覆蓋已存在的文件。</param> public void UnZip( string zipedFile, string strDirectory, string password, bool overWrite) { if ( string .IsNullOrEmpty(zipedFile)) { throw new ArgumentException(zipedFile); } if ( string .IsNullOrEmpty(strDirectory)) { throw new ArgumentException(strDirectory); } if ( string .IsNullOrEmpty(password)) { throw new ArgumentException(password); } if (strDirectory == "" ) { strDirectory = Directory.GetCurrentDirectory(); } if (!strDirectory.EndsWith( "\\" )) { strDirectory = strDirectory + "\\" ; } try { using (var s = new ZipInputStream(File.OpenRead(zipedFile))) { s.Password = password; ZipEntry theEntry; while ((theEntry = s.GetNextEntry()) != null ) { var directoryName = string .Empty; var pathToZip = theEntry.Name; if (pathToZip != "" ) { directoryName = Path.GetDirectoryName(pathToZip) + "\\" ; } var fileName = Path.GetFileName(pathToZip); Directory.CreateDirectory(strDirectory + directoryName); if (fileName == "" ) continue ; if ((!File.Exists(strDirectory + directoryName + fileName) || !overWrite) && (File.Exists(strDirectory + directoryName + fileName))) continue ; using (var streamWriter = File.Create(strDirectory + directoryName + fileName)) { var data = new byte [2048]; while ( true ) { var size = s.Read(data, 0, data.Length); if (size > 0) streamWriter.Write(data, 0, size); else break ; } streamWriter.Close(); } } s.Close(); } } catch (IOException ioex) { throw new IOException(ioex.Message); } catch (Exception ex) { throw new Exception(ex.Message); } } |
四.總結(jié):
以上是對SharpZipLib組件的相關(guān)介紹,本文的講解上比較的淺顯,如果需要深入的學(xué)習(xí)可以進(jìn)入官網(wǎng)進(jìn)行詳細(xì)的學(xué)習(xí)。組件的功能是很強大的,如何在項目中使用組件,完成我們在項目中需要實現(xiàn)的功能,這就是對每個開發(fā)者提出了要求,需要我們仔細(xì)的去考慮。
任何學(xué)習(xí)都需要我們自己去探索和思考,對于一個開發(fā)者來說,最重要的就是思考,因為在我們的職業(yè)生涯中,沒有什么的重要性能夠超過思考。如果有不足之處還望各位讀者包含,并留言指正。
原文鏈接:http://www.cnblogs.com/pengze0902/p/6159497.html