The best. NET open source free ZIP library DotNetZip (. NET component introduction III)

  • 2021-08-31 07:35:59
  • OfStack

In the project development, in addition to the display of data, more is the related operations of files, such as file creation and deletion, and file compression and decompression. There are many benefits of file compression, mainly in the aspect of file transmission, the benefits of file compression do not need to be repeated, because both developers and users have a deep understanding of the benefits of file compression. As for the principle of file compression, I have a simple introduction in another blog, so I will no longer introduce it here. What I need to know can be viewed.

NET provides two compression algorithms, GZip and Defalate, in the System. IO. Compression namespace. One of the compression components I will introduce today is the DotNetZip component.

1. DotNetZip component overview:

In the self-introduction of DotNetZip, it is claimed that "DotNetZip is the best open source ZIP library of NET". As for whether it is the best compression component, we will not evaluate it here. After all, each user's mentality and working environment are different, and the project has different requirements for components. When selecting components, developers need to measure them themselves. It is estimated that many people began to type words on the keyboard before they saw it. The title is I borrow the official propaganda slogan, so don't pay too much attention to these details.

DotNetZip-Zip decompression is available in C #, VB, any. NET language. DotNetZip is an FAST, free class library and toolset for manipulating zip files. Easily create, extract, or update zip files using VB, C #, or any. NET language. DotNetZip runs on an PC with the full. NET Framework, and also on mobile devices using. NET Compact Framework. Create and read zip files in VB, C # or any. NET language or any scripting environment.

The use environment of DotNetZip components, after all, the use environment of software is something every developer needs to consider. There is no absolute good thing in this world, and of course there is no absolute bad thing. Next, take a look at the description of the actual use environment:

1.1 Silverlight applications that dynamically create zip files.

2.1 ASP. NET applications that dynamically create ZIP files and allow browsers to download them.

3.1 Windows services that periodically pull up 1 directory for backup and archiving purposes.

4. Modify the WPF program for an existing archive-rename entries, delete entries from the archive, or add new entries to the archive.

5.1 Windows Forms application to create an AES encrypted zip archive for the privacy of archived content.

6. Extract or zip the SSIS script.

7. 1 administrative script in PowerShell or VBScript to perform backup and archiving.

8. The WCF service, which receives the zip file as an attachment and dynamically decompresses the zip into a stream for analysis.

9.1 old-fashioned ASP (VBScript) applications that generate an ZIP file for DotNetZIp via the COM interface.

10. An Windows Forms application that reads or updates an ODS file.

11. Create an zip file from the stream content, save to the stream, extract to the stream, and read from the stream.

12. Create a self-extracting file.

DotNetZip is a 100% managed code base that can be used with any. NET application-console, Winforms, WPF, ASP. NET, Sharepoint, Web service application, etc. New v 1.9. 1.6: Silverlight. It can also be used from scripting environments or environments with COM capabilities, such as Powershell scripts, VBScript, VBA, VB6, PHP, Perl, Javascript, and so on. zip files generated by DotNetZip are fully interoperable with Windows Explorer, Java applications, and applications running on Linux, regardless of the environment used.

This component is simple in design and easy to use. DotNetZip is packaged into a single DLL with a size of about 400k. It has no third-party dependence. It is medium trust, so it can be used by most hosting vendors. Compression is obtained by referencing DLL. The library supports zip cryptography, Unicode, ZIP64, stream input and output, AES encryption, multiple compression levels, self-extracting archiving, cross-region archiving and so on.

The above description comes from the official website, so it is no longer touting this component. What needs to be explained here is that the selection and use of components mainly depends on the actual situation of the project. For details, see: http://dotnetzip.codeplex.com/

2. Analysis of 2. DotNetZip related core classes and methods:

Because you downloaded the DLL file, you decompiled the DLL file with. NET Reflector to view the source code. I mainly introduce some classes and methods under 1, but I don't introduce them completely. First of all, due to the limited space, it is totally unnecessary, because for developers, it is not necessary to know all these classes. In actual development, you can call corresponding methods according to API. These skills should be possessed by a developer.

1. AddEntry (), Save (), and IsZipFile () methods of the ZipFile class:


 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 () reads the data stream:


 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;
}

Above is the ZipFile class of some methods of analysis, provides the source code of the component of some methods, as for the interpretation of the source code is not very difficult, as for the component of API, you can download the DLL file, you can directly view the corresponding methods and attributes, do not do a detailed introduction here.

3. DotNetZip component usage example:

The above is a little parsing of this component. Next, let's look at an example:

1. Compress the ZIP file:


/// <summary>
  ///  Compression ZIP Documents 
  ///  Support multiple files and directories, or multiple files and directories 1 Compression 
  /// </summary>
  /// <param name="list"> Collection of files or directories to be compressed </param>
  /// <param name="strZipName"> Compressed file name </param>
  /// <param name="isDirStruct"> Whether to compress by directory structure </param>
  /// <returns> Success: true/ Failure: 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
   {
    // Set the code to solve the Chinese garbled code when compressing files 
    using (var zip = new ZipFile(Encoding.Default))
    {
     foreach (var path in list)
     {
      // Take directory name 
      var fileName = Path.GetFileName(path);
      // If it is a directory 
      if (Directory.Exists(path))
      {
       // Compress by directory structure 
       if (isDirStruct)
       {
        zip.AddDirectory(path, fileName);
       }
       else
       {
        // Files in the directory are compressed to Zip Root directory of 
        zip.AddDirectory(path);
       }
      }
      if (File.Exists(path))
      {
       zip.AddFile(path);
      }
     }
     // Compression 
     zip.Save(strZipName);
     return true;
    }
   }
   catch (Exception ex)
   {
    throw new Exception(ex.Message);
   }
  }

2. Unzip the ZIP file:


/// <summary>
  ///  Decompression ZIP Documents 
  /// </summary>
  /// <param name="strZipPath"> To be decompressed ZIP Documents </param>
  /// <param name="strUnZipPath"> Extracted directory </param>
  /// <param name="overWrite"> Whether to override </param>
  /// <returns> Success: true/ Failure: 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
    };
    // Set the code to solve the Chinese garbled code when decompressing files 
    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. Get the ZIP compressed stream object for the specified input stream:


/// <summary>
  ///  Object for the specified input stream ZIP Compressed stream object 
  /// </summary>
  /// <param name="sourceStream"> Source data stream </param>
  /// <param name="entryName"> Entity name </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. Gets the ZIP unzipped stream object for the specified byte array:


/// <summary>
  ///  Object of the specified byte array ZIP Decompress flow object 
  ///  The current method is only applicable to only 1 Compressed package of compressed files, that is, only the first in the compressed package is taken in the method 1 Compressed files 
  /// </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 Method is manipulated in the ms For subsequent use, you must first set the Stream The position is zero, otherwise no data will be read later 
      //  Returns the Stream Object before the 1 Secondary position zeroing action 
      decompressedStream.Position = 0;
     }
    }
   }
   catch(Exception ex)
   {
    throw new Exception(ex.Message);
   }
   return decompressedStream;
  }

4. Summary:

The above are some parsing and method examples of DotNetZip components. As to whether this component is the best. NET compression component, this will not be evaluated. When choosing components, the first consideration is open source, the second is free, and the last consideration is efficiency and practicality. After all, 1 situation in China is clear to all developers (not mentioning foreign countries because I don't know the situation abroad). Customers need to reduce costs and customize components. However, I think charging should be a trend. After all, all products need personnel to maintain and develop. There are some shortcomings in the above blog posts, and I hope to correct them.


Related articles: