詳解最好的.NET開源免費(fèi)ZIP庫DotNetZip(.NET組件介紹之三)
在項(xiàng)目開發(fā)中,除了對數(shù)據(jù)的展示更多的就是對文件的相關(guān)操作,例如文件的創(chuàng)建和刪除,以及文件的壓縮和解壓。文件壓縮的好處有很多,主要就是在文件傳輸?shù)姆矫?,文件壓縮的好處就不需要贅述,因?yàn)闊o論是開發(fā)者,還是使用者對于文件壓縮的好處都是深有體會。至于文件壓縮的原理,在我的另一篇博客中有簡單的介紹,在這里就不再做介紹,需要了解的可以查看。
.NET在System.IO.Compression命名空間中提供了GZip、Defalate兩種壓縮算法。今天我要介紹的一種壓縮組件是DotNetZip組件。
一.DotNetZip組件概述:
在DotNetZip的自我介紹中號稱是”DotNetZip是.NET最好的開源ZIP庫“,至于是不是最好的壓縮組件,在這里就不做評價(jià),畢竟每個使用者的心態(tài)和工作環(huán)境不同,項(xiàng)目對組件的需求也不同,在選擇組件的時候,就需要開發(fā)者自己衡量了。估計(jì)很多人還沒有看到這里就開始在鍵盤上敲字吐槽了,標(biāo)題是我借用官方對外的宣傳口號,不用太在意這些細(xì)節(jié)。
DotNetZip - Zip和解壓縮在C#,VB,任何.NET語言都可使用。DotNetZip是一個FAST,免費(fèi)類庫和用于操縱zip文件的工具集。 使用VB,C#或任何.NET語言輕松創(chuàng)建,解壓縮或更新zip文件。DotNetZip在具有完整.NET Framework的PC上運(yùn)行,并且還在使用.NET Compact Framework的移動設(shè)備上運(yùn)行。在VB,C?;蛉魏?NET語言或任何腳本環(huán)境中創(chuàng)建和讀取zip文件。
DotNetZip組件的使用環(huán)境,畢竟軟件的使用環(huán)境是每一個開發(fā)者都需要考慮的,這個世界沒有絕對的好事,當(dāng)然也沒有絕對的壞事。接下來看一下其實(shí)用環(huán)境的說明吧:
1.一個動態(tài)創(chuàng)建zip文件的Silverlight應(yīng)用程序。
2.一個ASP.NET應(yīng)用程序,動態(tài)創(chuàng)建ZIP文件并允許瀏覽器下載它們。
3.一個Windows服務(wù),定期地為了備份和歸檔目的上拉一個目錄。
4.修改現(xiàn)有歸檔的WPF程序 - 重命名條目,從歸檔中刪除條目或向歸檔中添加新條目。
5.一個Windows窗體應(yīng)用程序,用于為歸檔內(nèi)容的隱私創(chuàng)建AES加密的zip存檔。
6.解壓縮或拉鏈的SSIS腳本。
7.PowerShell或VBScript中的一個管理腳本,用于執(zhí)行備份和歸檔。
8.WCF服務(wù),接收作為附件的zip文件,并動態(tài)地將zip解壓縮到流以進(jìn)行分析。
9.一個老式的ASP(VBScript)應(yīng)用程序,通過COM接口為DotNetZIp生成一個ZIP文件。
10.讀取或更新ODS文件的Windows Forms應(yīng)用程序。
11.從流內(nèi)容創(chuàng)建zip文件,保存到流,提取到流,從流讀取。
12.創(chuàng)建自解壓檔案。
DotNetZip是一個100%的托管代碼庫,可用于任何.NET應(yīng)用程序 - 控制臺,Winforms,WPF,ASP.NET,Sharepoint,Web服務(wù)應(yīng)用程序等。 新的v1.9.1.6:Silverlight。 它還可以從腳本環(huán)境或具有COM功能的環(huán)境(如Powershell腳本,VBScript,VBA,VB6,PHP,Perl,Javascript等)中使用。 無論使用什么環(huán)境,DotNetZip生成的zip文件可與Windows資源管理器以及Java應(yīng)用程序,在Linux上運(yùn)行的應(yīng)用程序完全互操作。
該組件設(shè)計(jì)簡單,易于使用。 DotNetZip打包為一個單一的DLL,大小約400k。 它沒有第三方依賴。 它是中等信任,因此可以在大多數(shù)托管商使用。 通過引用DLL來獲取壓縮。 該庫支持zip密碼,Unicode,ZIP64,流輸入和輸出,AES加密,多個壓縮級別,自解壓縮存檔,跨區(qū)存檔等。
以上的一些描述來自與官網(wǎng),就不再吹捧這個組件了,在這里需要說明的是在組件的選擇和使用上,主要取決與項(xiàng)目的實(shí)際情況。詳情見:http://dotnetzip.codeplex.com/
二.DotNetZip相關(guān)核心類和方法解析:
由于下載的是DLL文件,還是采用.NET Reflector對DLL文件進(jìn)行反編譯,以此查看源代碼。一下主要介紹一些類和方法,沒有完全介紹,首先是由于篇幅所限,其實(shí)是完全沒有必要,因?yàn)閷τ陂_發(fā)者而言,沒有必要全部了解這些類,在實(shí)際的開發(fā)中,可以根據(jù)API進(jìn)行對應(yīng)的方法調(diào)用,這些技能應(yīng)該是一個開發(fā)人員應(yīng)該具備的。
1.ZipFile類的AddEntry()、Save()和IsZipFile()方法:
public ZipEntry AddEntry(string entryName, WriteDelegate writer)
{
ZipEntry ze = ZipEntry.CreateForWriter(entryName, writer);
if (this.Verbose)
{
this.StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
}
return this._InternalAddEntry(ze);
}
public void Save()
{
try
{
bool flag = false;
this._saveOperationCanceled = false;
this._numberOfSegmentsForMostRecentSave = 0;
this.OnSaveStarted();
if (this.WriteStream == null)
{
throw new BadStateException("You haven't specified where to save the zip.");
}
if (((this._name != null) && this._name.EndsWith(".exe")) && !this._SavingSfx)
{
throw new BadStateException("You specified an EXE for a plain zip file.");
}
if (!this._contentsChanged)
{
this.OnSaveCompleted();
if (this.Verbose)
{
this.StatusMessageTextWriter.WriteLine("No save is necessary....");
}
}
else
{
this.Reset(true);
if (this.Verbose)
{
this.StatusMessageTextWriter.WriteLine("saving....");
}
if ((this._entries.Count >= 0xffff) && (this._zip64 == Zip64Option.Default))
{
throw new ZipException("The number of entries is 65535 or greater. Consider setting the UseZip64WhenSaving property on the ZipFile instance.");
}
int current = 0;
ICollection<ZipEntry> entries = this.SortEntriesBeforeSaving ? this.EntriesSorted : this.Entries;
foreach (ZipEntry entry in entries)
{
this.OnSaveEntry(current, entry, true);
entry.Write(this.WriteStream);
if (this._saveOperationCanceled)
{
break;
}
current++;
this.OnSaveEntry(current, entry, false);
if (this._saveOperationCanceled)
{
break;
}
if (entry.IncludedInMostRecentSave)
{
flag |= entry.OutputUsedZip64.Value;
}
}
if (!this._saveOperationCanceled)
{
ZipSegmentedStream writeStream = this.WriteStream as ZipSegmentedStream;
this._numberOfSegmentsForMostRecentSave = (writeStream != null) ? writeStream.CurrentSegment : 1;
bool flag2 = ZipOutput.WriteCentralDirectoryStructure(this.WriteStream, entries, this._numberOfSegmentsForMostRecentSave, this._zip64, this.Comment, new ZipContainer(this));
this.OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive);
this._hasBeenSaved = true;
this._contentsChanged = false;
flag |= flag2;
this._OutputUsesZip64 = new bool?(flag);
if ((this._name != null) && ((this._temporaryFileName != null) || (writeStream != null)))
{
this.WriteStream.Dispose();
if (this._saveOperationCanceled)
{
return;
}
if (this._fileAlreadyExists && (this._readstream != null))
{
this._readstream.Close();
this._readstream = null;
foreach (ZipEntry entry2 in entries)
{
ZipSegmentedStream stream2 = entry2._archiveStream as ZipSegmentedStream;
if (stream2 != null)
{
stream2.Dispose();
}
entry2._archiveStream = null;
}
}
string path = null;
if (File.Exists(this._name))
{
path = this._name + "." + Path.GetRandomFileName();
if (File.Exists(path))
{
this.DeleteFileWithRetry(path);
}
File.Move(this._name, path);
}
this.OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive);
File.Move((writeStream != null) ? writeStream.CurrentTempName : this._temporaryFileName, this._name);
this.OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive);
if (path != null)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
}
catch
{
}
}
this._fileAlreadyExists = true;
}
NotifyEntriesSaveComplete(entries);
this.OnSaveCompleted();
this._JustSaved = true;
}
}
}
finally
{
this.CleanupAfterSaveOperation();
}
}
public static bool IsZipFile(Stream stream, bool testExtract)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
bool flag = false;
try
{
if (!stream.CanRead)
{
return false;
}
Stream @null = Stream.Null;
using (ZipFile file = Read(stream, null, null, null))
{
if (testExtract)
{
foreach (ZipEntry entry in file)
{
if (!entry.IsDirectory)
{
entry.Extract(@null);
}
}
}
}
flag = true;
}
catch (IOException)
{
}
catch (ZipException)
{
}
return flag;
}
2.Read()讀取數(shù)據(jù)流:
private static ZipFile Read(Stream zipStream, TextWriter statusMessageWriter, Encoding encoding, EventHandler<ReadProgressEventArgs> readProgress)
{
if (zipStream == null)
{
throw new ArgumentNullException("zipStream");
}
ZipFile zf = new ZipFile {
_StatusMessageTextWriter = statusMessageWriter,
_alternateEncoding = encoding ?? DefaultEncoding,
_alternateEncodingUsage = ZipOption.Always
};
if (readProgress != null)
{
zf.ReadProgress += readProgress;
}
zf._readstream = (zipStream.Position == 0L) ? zipStream : new OffsetStream(zipStream);
zf._ReadStreamIsOurs = false;
if (zf.Verbose)
{
zf._StatusMessageTextWriter.WriteLine("reading from stream...");
}
ReadIntoInstance(zf);
return zf;
}
以上是對ZipFile類的一些方法的解析,提供了該組件的一些方法的源碼,至于源碼的解讀上難度不是很大,至于該組件的API,可以在下載DLL文件后,可以直接查看相應(yīng)的方法和屬性,在這里就不做詳細(xì)的介紹。
三.DotNetZip組件使用實(shí)例:
以上是對該組件的一些解析,接下來我們看看實(shí)例:
1.壓縮ZIP文件:
/// <summary>
/// 壓縮ZIP文件
/// 支持多文件和多目錄,或是多文件和多目錄一起壓縮
/// </summary>
/// <param name="list">待壓縮的文件或目錄集合</param>
/// <param name="strZipName">壓縮后的文件名</param>
/// <param name="isDirStruct">是否按目錄結(jié)構(gòu)壓縮</param>
/// <returns>成功:true/失?。篺alse</returns>
public static bool CompressMulti(List<string> list, string strZipName, bool isDirStruct)
{
if (list == null)
{
throw new ArgumentNullException("list");
}
if (string.IsNullOrEmpty(strZipName))
{
throw new ArgumentNullException(strZipName);
}
try
{
//設(shè)置編碼,解決壓縮文件時中文亂碼
using (var zip = new ZipFile(Encoding.Default))
{
foreach (var path in list)
{
//取目錄名稱
var fileName = Path.GetFileName(path);
//如果是目錄
if (Directory.Exists(path))
{
//按目錄結(jié)構(gòu)壓縮
if (isDirStruct)
{
zip.AddDirectory(path, fileName);
}
else
{
//目錄下的文件都壓縮到Zip的根目錄
zip.AddDirectory(path);
}
}
if (File.Exists(path))
{
zip.AddFile(path);
}
}
//壓縮
zip.Save(strZipName);
return true;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
2.解壓ZIP文件:
/// <summary>
/// 解壓ZIP文件
/// </summary>
/// <param name="strZipPath">待解壓的ZIP文件</param>
/// <param name="strUnZipPath">解壓的目錄</param>
/// <param name="overWrite">是否覆蓋</param>
/// <returns>成功:true/失?。篺alse</returns>
public static bool Decompression(string strZipPath, string strUnZipPath, bool overWrite)
{
if (string.IsNullOrEmpty(strZipPath))
{
throw new ArgumentNullException(strZipPath);
}
if (string.IsNullOrEmpty(strUnZipPath))
{
throw new ArgumentNullException(strUnZipPath);
}
try
{
var options = new ReadOptions
{
Encoding = Encoding.Default
};
//設(shè)置編碼,解決解壓文件時中文亂碼
using (var zip = ZipFile.Read(strZipPath, options))
{
foreach (var entry in zip)
{
if (string.IsNullOrEmpty(strUnZipPath))
{
strUnZipPath = strZipPath.Split('.').First();
}
entry.Extract(strUnZipPath,overWrite
? ExtractExistingFileAction.OverwriteSilently
: ExtractExistingFileAction.DoNotOverwrite);
}
return true;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
3.得到指定的輸入流的ZIP壓縮流對象:
/// <summary>
/// 得到指定的輸入流的ZIP壓縮流對象
/// </summary>
/// <param name="sourceStream">源數(shù)據(jù)流</param>
/// <param name="entryName">實(shí)體名稱</param>
/// <returns></returns>
public static Stream ZipCompress(Stream sourceStream, string entryName = "zip")
{
if (sourceStream == null)
{
throw new ArgumentNullException("sourceStream");
}
var compressedStream = new MemoryStream();
long sourceOldPosition = 0;
try
{
sourceOldPosition = sourceStream.Position;
sourceStream.Position = 0;
using (var zip = new ZipFile())
{
zip.AddEntry(entryName, sourceStream);
zip.Save(compressedStream);
compressedStream.Position = 0;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
try
{
sourceStream.Position = sourceOldPosition;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
return compressedStream;
}
4.得到指定的字節(jié)數(shù)組的ZIP解壓流對象:
/// <summary>
/// 得到指定的字節(jié)數(shù)組的ZIP解壓流對象
/// 當(dāng)前方法僅適用于只有一個壓縮文件的壓縮包,即方法內(nèi)只取壓縮包中的第一個壓縮文件
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static Stream ZipDecompress(byte[] data)
{
Stream decompressedStream = new MemoryStream();
if (data == null) return decompressedStream;
try
{
var dataStream = new MemoryStream(data);
using (var zip = ZipFile.Read(dataStream))
{
if (zip.Entries.Count > 0)
{
zip.Entries.First().Extract(decompressedStream);
// Extract方法中會操作ms,后續(xù)使用時必須先將Stream位置歸零,否則會導(dǎo)致后續(xù)讀取不到任何數(shù)據(jù)
// 返回該Stream對象之前進(jìn)行一次位置歸零動作
decompressedStream.Position = 0;
}
}
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
return decompressedStream;
}
四.總結(jié):
以上是對DotNetZip組件的一些解析和方法實(shí)例,至于這款組件是不是最好的.NET壓縮組件,這個就不做評價(jià)。個人在選擇組件的時候,首先考慮的是開源,其次是免費(fèi),最后再考慮效率和實(shí)用性,畢竟在國內(nèi)的一些情況是所有開發(fā)者都清楚的(不提國外是由于我不知道國外的情況)??蛻粜枰档统杀?,并且組件要可以進(jìn)行定制。不過個人認(rèn)為收費(fèi)應(yīng)該是一種趨勢,畢竟所有的產(chǎn)品都是需要人員進(jìn)行維護(hù)和開發(fā)。以上的博文中有不足之處,還望多多指正。
- .NET 開源配置組件 AgileConfig的使用簡介
- ASP.NET開源導(dǎo)入導(dǎo)出庫Magicodes.IE完成Csv導(dǎo)入導(dǎo)出的方法
- 詳解開源免費(fèi)且穩(wěn)定實(shí)用的.NET PDF打印組件itextSharp(.NET組件介紹之八)
- 詳解一款開源免費(fèi)的.NET文檔操作組件DocX(.NET組件介紹之一)
- 詳解免費(fèi)開源的DotNet二維碼操作組件ThoughtWorks.QRCode(.NET組件介紹之四)
- 詳解免費(fèi)開源的.NET多類型文件解壓縮組件SharpZipLib(.NET組件介紹之七)
- 詳解免費(fèi)開源的DotNet任務(wù)調(diào)度組件Quartz.NET(.NET組件介紹之五)
- .NET中開源文檔操作組件DocX的介紹與使用
- 基于.NET平臺常用的框架和開源程序整理
- .NET 開源項(xiàng)目Polly的簡單介紹
相關(guān)文章
asp.net(C#)生成Code39條形碼實(shí)例 條碼槍可以掃描出
這篇文章主要介紹了asp.net(C#)生成Code39條形碼實(shí)例 條碼槍可以掃描出。需要的朋友可以過來參考下,希望對大家有所幫助2014-02-02
.NET微服務(wù)架構(gòu)CI/CD自動構(gòu)建Jenkins+Gitee
這篇文章介紹了.NET使用微服務(wù)架構(gòu)CI/CD自動構(gòu)建Jenkins+Gitee的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01
ASP .NET Core API發(fā)布與部署以及遇到的坑和解決方法
這篇文章主要介紹了ASP .NET Core API發(fā)布與部署以及遇到的坑和解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
解析WPF實(shí)現(xiàn)音頻文件循環(huán)順序播放的解決方法
本篇文章是對WPF實(shí)現(xiàn)音頻文件循環(huán)順序播放的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Asp.Net Core利用xUnit進(jìn)行主機(jī)級別的網(wǎng)絡(luò)集成測試詳解
這篇文章主要給大家介紹了關(guān)于Asp.Net Core利用xUnit進(jìn)行主機(jī)級別的網(wǎng)絡(luò)集成測試的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們來一起看看吧2018-12-12
gridview行索引獲取方法及實(shí)現(xiàn)代碼(非js版)
前一篇是用Javascript獲取GridView的行索引,此篇Insus.NET使用非Javascript獲取GridView的行索引,感興趣的朋友可以了解下2013-01-01

