最好的.NET開源免費ZIP庫DotNetZip(.NET組件介紹之三)

来源:http://www.cnblogs.com/pengze0902/archive/2016/12/06/6124659.html
-Advertisement-
Play Games

在項目開發中,除了對數據的展示更多的就是對文件的相關操作,例如文件的創建和刪除,以及文件的壓縮和解壓。文件壓縮的好處有很多,主要就是在文件傳輸的方面,文件壓縮的好處就不需要贅述,因為無論是開發者,還是使用者對於文件壓縮的好處都是深有體會。至於文件壓縮的原理,在我的另一篇博客中有簡單的介紹,在這裡就不 ...


   在項目開發中,除了對數據的展示更多的就是對文件的相關操作,例如文件的創建和刪除,以及文件的壓縮和解壓。文件壓縮的好處有很多,主要就是在文件傳輸的方面,文件壓縮的好處就不需要贅述,因為無論是開發者,還是使用者對於文件壓縮的好處都是深有體會。至於文件壓縮的原理,在我的另一篇博客中有簡單的介紹,在這裡就不再做介紹,需要瞭解的可以查看。

   .NET在System.IO.Compression命名空間中提供了GZip、Defalate兩種壓縮演算法。今天我要介紹的一種壓縮組件是DotNetZip組件。

一.DotNetZip組件概述:

   在DotNetZip的自我介紹中號稱是”DotNetZip是.NET最好的開源ZIP庫“,至於是不是最好的壓縮組件,在這裡就不做評價,畢竟每個使用者的心態和工作環境不同,項目對組件的需求也不同,在選擇組件的時候,就需要開發者自己衡量了。估計很多人還沒有看到這裡就開始在鍵盤上敲字吐槽了,標題是我借用官方對外的宣傳口號,不用太在意這些細節。

   DotNetZip - Zip和解壓縮在C#,VB,任何.NET語言都可使用。DotNetZip是一個FAST,免費類庫和用於操縱zip文件的工具集。 使用VB,C#或任何.NET語言輕鬆創建,解壓縮或更新zip文件。DotNetZip在具有完整.NET Framework的PC上運行,並且還在使用.NET Compact Framework的移動設備上運行。在VB,C#或任何.NET語言或任何腳本環境中創建和讀取zip文件。

  DotNetZip組件的使用環境,畢竟軟體的使用環境是每一個開發者都需要考慮的,這個世界沒有絕對的好事,當然也沒有絕對的壞事。接下來看一下其實用環境的說明吧:

  1.一個動態創建zip文件的Silverlight應用程式。

  2.一個ASP.NET應用程式,動態創建ZIP文件並允許瀏覽器下載它們。

  3.一個Windows服務,定期地為了備份和歸檔目的上拉一個目錄。

  4.修改現有歸檔的WPF程式 - 重命名條目,從歸檔中刪除條目或向歸檔中添加新條目。

  5.一個Windows窗體應用程式,用於為歸檔內容的隱私創建AES加密的zip存檔。

  6.解壓縮或拉鏈的SSIS腳本。

  7.PowerShell或VBScript中的一個管理腳本,用於執行備份和歸檔。

  8.WCF服務,接收作為附件的zip文件,並動態地將zip解壓縮到流以進行分析。

  9.一個老式的ASP(VBScript)應用程式,通過COM介面為DotNetZIp生成一個ZIP文件。

  10.讀取或更新ODS文件的Windows Forms應用程式。

  11.從流內容創建zip文件,保存到流,提取到流,從流讀取。

  12.創建自解壓檔案。

   DotNetZip是一個100%的托管代碼庫,可用於任何.NET應用程式 - 控制台,Winforms,WPF,ASP.NET,Sharepoint,Web服務應用程式等。 新的v1.9.1.6:Silverlight。 它還可以從腳本環境或具有COM功能的環境(如Powershell腳本,VBScript,VBA,VB6,PHP,Perl,Javascript等)中使用。 無論使用什麼環境,DotNetZip生成的zip文件可與Windows資源管理器以及Java應用程式,在Linux上運行的應用程式完全互操作。

    該組件設計簡單,易於使用。 DotNetZip打包為一個單一的DLL,大小約400k。 它沒有第三方依賴。 它是中等信任,因此可以在大多數托管商使用。 通過引用DLL來獲取壓縮。 該庫支持zip密碼,Unicode,ZIP64,流輸入和輸出,AES加密,多個壓縮級別,自解壓縮存檔,跨區存檔等。

   以上的一些描述來自與官網,就不再吹捧這個組件了,在這裡需要說明的是在組件的選擇和使用上,主要取決與項目的實際情況。詳情見:http://dotnetzip.codeplex.com/

二.DotNetZip相關核心類和方法解析:

    由於下載的是DLL文件,還是採用.NET Reflector對DLL文件進行反編譯,以此查看源代碼。一下主要介紹一些類和方法,沒有完全介紹,首先是由於篇幅所限,其實是完全沒有必要,因為對於開發者而言,沒有必要全部瞭解這些類,在實際的開發中,可以根據API進行對應的方法調用,這些技能應該是一個開發人員應該具備的。

   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()讀取數據流:

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文件後,可以直接查看相應的方法和屬性,在這裡就不做詳細的介紹。

三.DotNetZip組件使用實例:

   以上是對該組件的一些解析,接下來我們看看實例:

1.壓縮ZIP文件:

        /// <summary>
        /// 壓縮ZIP文件
        /// 支持多文件和多目錄,或是多文件和多目錄一起壓縮
        /// </summary>
        /// <param name="list">待壓縮的文件或目錄集合</param>
        /// <param name="strZipName">壓縮後的文件名</param>
        /// <param name="isDirStruct">是否按目錄結構壓縮</param>
        /// <returns>成功:true/失敗:false</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
            {
                //設置編碼,解決壓縮文件時中文亂碼
                using (var zip = new ZipFile(Encoding.Default))
                {
                    foreach (var path in list)
                    {
                        //取目錄名稱
                        var fileName = Path.GetFileName(path);
                        //如果是目錄
                        if (Directory.Exists(path))
                        {
                            //按目錄結構壓縮
                            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/失敗:false</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
                };
                //設置編碼,解決解壓文件時中文亂碼
                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">源數據流</param>
        /// <param name="entryName">實體名稱</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.得到指定的位元組數組的ZIP解壓流對象:

        /// <summary>
        /// 得到指定的位元組數組的ZIP解壓流對象
        /// 當前方法僅適用於只有一個壓縮文件的壓縮包,即方法內只取壓縮包中的第一個壓縮文件
        /// </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,後續使用時必須先將Stream位置歸零,否則會導致後續讀取不到任何數據
                        // 返回該Stream對象之前進行一次位置歸零動作
                        decompressedStream.Position = 0;
                    }
                }
            }
            catch(Exception ex)
            {
                throw new Exception(ex.Message);
            }
            return decompressedStream;
        }

四.總結:

   以上是對DotNetZip組件的一些解析和方法實例,至於這款組件是不是最好的.NET壓縮組件,這個就不做評價。個人在選擇組件的時候,首先考慮的是開源,其次是免費,最後再考慮效率和實用性,畢竟在國內的一些情況是所有開發者都清楚的(不提國外是由於我不知道國外的情況)。客戶需要降低成本,並且組件要可以進行定製。不過個人認為收費應該是一種趨勢,畢竟所有的產品都是需要人員進行維護和開發。以上的博文中有不足之處,還望多多指正。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • @echo offInstallutil.exe 程式目錄 F:\test\TestWindows.exe 服務程式目錄@sc start "服務名稱"@sc config "服務名稱" start= 啟動方式:AUTO@echo off@echo 服務安裝並啟動完成pause 示例: @echo ...
  • ...
  • 1.開發人員在火狐瀏覽器里經常使用的工具有Firebug,httprequester,restclient......火狐瀏覽器有一些強大的插件供開發人員使用!需要的可以在附加組件中擴展。 2.httprequester,也是可以在附加組件中獲得的,你只要輸入這個名詞,搜索安裝。 web開發人員一般 ...
  • Ext.NET 4.1 最新版本破解 今天在將Ext.NET 4.1版本的程式發佈到公網時居然要license(localhost和127.0.0.1不收費),而且一年$4999,突然間覺得這是什麼鬼,居然還收費!如圖: 大大的一個UNLICENSED! 網上搜索破解方法,好像都沒什麼用,唯一有啟發 ...
  • 1、重覆輸入一個數,判斷該數是否是質數,輸入q結束?質數的判斷用方法來實現bool IsPrime(int number) 1 static void Main(string[] args) 2 { 3 // 要求:重覆讓用戶輸入一個數,判斷該數是否是質數,輸入q結束? 質數的判斷用方法來實現boo ...
  • params參數練習 1 namespace Test 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //params 構造函數聲明數組,可變數組長度 8 UseParam1(4,2,3); 9 UserParam2( ...
  • petapoco是個基於T4模板的輕量級ORM,好用效率高,具體介紹略了 獲取註釋基本原理是調用資料庫::fn_listextendedproperty函數,獲取擴展屬性MS_Description technet參考資料:sys.fn_listextendedproperty (Transact- ...
  • 最近比較忙,前期忙公司手機端介面項目,各種開發+調試+發佈現在幾乎上線無問題了;雖然公司項目忙不過在期間抽空做了兩件個人覺得有意義的事情,一者使用aspnetcore開發了個人線上項目(要說線上其實只能ip訪問,沒有功能變數名稱哈哈),其架構組成由:aspnetcore1.0.0+redis+ postgr ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...