详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
前面介绍了六种.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():
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():
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():
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():
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.压缩单个文件:
/// <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. 压缩单个文件:
/// <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.压缩多层目录:
/// <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.递归遍历目录:
/// <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 文件:
/// <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组件的相关介绍,本文的讲解上比较的浅显,如果需要深入的学习可以进入官网进行详细的学习。组件的功能是很强大的,如何在项目中使用组件,完成我们在项目中需要实现的功能,这就是对每个开发者提出了要求,需要我们仔细的去考虑。
任何学习都需要我们自己去探索和思考,对于一个开发者来说,最重要的就是思考,因为在我们的职业生涯中,没有什么的重要性能够超过思考。如果有不足之处还望各位读者包含,并留言指正。
推荐阅读
-
详解免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)
-
详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
-
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
-
详解开源免费且稳定实用的.NET PDF打印组件itextSharp(.NET组件介绍之八)
-
详解免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)
-
详解开源免费且稳定实用的.NET PDF打印组件itextSharp(.NET组件介绍之八)
-
详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
-
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)