前面介绍了六种.NET组件,其中有一种组件是写文件的压缩和解压,现在介绍另一种文件的解压缩组件SharpZipLib。在这个组件介绍系列中,只为简单的介绍组件的背景和简单的应用,读者在阅读时可以结合官网的相关介绍和在本地实际操作。
相关的组件功能非常强大,在笔者的介绍中只是提及到简单的应用,需要了解更多的操作和特性,可以根据官网介绍,或者查看DLL文件的相关类和方法,以此来扩展相关的业务需要。
SharpZipLib是一个完全在C#中为.NET平台编写的Zip,GZip,Tar和BZip2库。
一.SharpZipLib组件概述:
ziplib(SharpZipLib,以前的NZipLib)是一个完全在C#为.NET平台编写的Zip,GZip,Tar和BZip2库。它实现为一个程序集(可安装在GAC中),因此可以轻松地集成到其他项目(任何.NET语言)中。 #ziplib的创建者这样说:“我已经将zip库移植到C#,因为我需要gzip / zip压缩,我不想使用libzip.dll或类似的东西我想要的所有在纯C#“。
SharpZipLib官网提供的下载操作:.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下发布,遵守开源协议。
二.SharpZipLib核心类和方法介绍:
以上简单的介绍了SharpZipLib组件的相关背景,现在具体看一下该组件的相关核心类和方法:
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">要进行压缩的文件名</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)
{
// 先当作目录处理如果存在这个目录就递归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);
}
}
|
四.总结:
以上是对SharpZipLib组件的相关介绍,本文的讲解上比较的浅显,如果需要深入的学习可以进入官网进行详细的学习。组件的功能是很强大的,如何在项目中使用组件,完成我们在项目中需要实现的功能,这就是对每个开发者提出了要求,需要我们仔细的去考虑。
任何学习都需要我们自己去探索和思考,对于一个开发者来说,最重要的就是思考,因为在我们的职业生涯中,没有什么的重要性能够超过思考。如果有不足之处还望各位读者包含,并留言指正。
原文链接:http://www.cnblogs.com/pengze0902/p/6159497.html