Detailed explanation of the best .NET open source free ZIP library DotNetZip (introduction of .NET components), zipdotnetzip
In project development, in addition to displaying data, more related operations are performed on files, such as file creation and deletion, and file compression and decompression. There are many benefits of file compression, mainly in terms of file transfer, and the benefits of file compression need not be repeated, because both developers and users have a deep understanding of the benefits of file compression. As for the principle of file compression, there is a brief introduction in my other blog. I won't introduce it here, you can check it if you need to know.
.NET provides GZip and Defalate compression algorithms in the System.IO.Compression namespace. One compression component I will introduce today is the DotNetZip component.
I. DotNetZip component overview:
In the self-introduction of DotNetZip, it is called "DotNetZip is the best open source ZIP library for .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. Project The requirements for components are also different. When selecting components, developers need to measure it themselves. It is estimated that many people have started typing on the keyboard before seeing it here. The title is I borrow the official publicity slogan. Don't worry too much about these details.
DotNetZip-Zip and decompression in C #, VB, any .NET language can be used. DotNetZip is a FAST, free class library and toolset for manipulating zip files. Easily create, decompress or update zip files using VB, C # or any .NET language. DotNetZip runs on a PC with a full .NET Framework and also runs on mobile devices using the .NET Compact Framework. Create and read zip files in VB, C # or any .NET language or any scripting environment.
The environment in which DotNetZip components are used. After all, the environment in which software is used must be considered by every developer. There is no absolute good thing in this world, and certainly no bad thing. Let ’s take a look at its practical environment:
1. A Silverlight application that dynamically creates a zip file.
2. An ASP.NET application that dynamically creates ZIP files and allows browsers to download them.
3. A Windows service that regularly pulls up a directory for backup and archive purposes.
4. Modify the existing archived WPF program-Rename entries, delete entries from the archive or add new entries to the archive.
5. A Windows Forms application for creating AES-encrypted zip archives for the privacy of archived content.
6. Unzip or zip the SSIS script.
7. A management script in PowerShell or VBScript for performing backups and archives.
8. A WCF service that receives a zip file as an attachment and dynamically decompresses the zip to a stream for analysis.
9. An old-fashioned ASP (VBScript) application generates a ZIP file for DotNetZIp via a COM interface.
10. A Windows Forms application that reads or updates the ODS file.
11. Create zip file from stream content, save to stream, extract to stream, and read from stream.
12. Create a self-extracting archive.
DotNetZip is a 100% managed code library that can be used in any .NET application-console, Winforms, WPF, ASP.NET, Sharepoint, web services applications, etc. New v1.9.1.6: Silverlight. It can also be used from a scripting environment or an environment with COM capabilities (such as Powershell scripting, VBScript, VBA, VB6, PHP, Perl, Javascript, etc.). Regardless of the environment, the zip file generated by DotNetZip is fully interoperable with Windows Explorer and Java applications, applications running on Linux.
The component is designed to be simple and easy to use. DotNetZip is packaged as a single DLL with a size of about 400k. It has no third-party dependencies. It's medium trust, so it can be used by most hosters. Get the compression by referencing the DLL. The library supports zip passwords, Unicode, ZIP64, stream input and output, AES encryption, multiple compression levels, self-extracting archives, cross-zone archives, and more.
Some of the above descriptions are from the official website, and this component is no longer touted. What needs to be explained here is that the selection and use of components mainly depends on the actual situation of the project. See: http://dotnetzip.codeplex.com/
Analysis of DotNetZip related core classes and methods:
Since the DLL file was downloaded, .NET Reflector was used to decompile the DLL file to view the source code. The following mainly introduces some classes and methods, but they are not completely introduced. First of all, due to space limitations, it is actually not necessary at all, because for developers, it is not necessary to fully understand these classes. In actual development, you can correspond to the API Method calls, these skills should be what a developer should have.
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;
}
The above is the analysis of some methods of the ZipFile class, and provides the source code of some methods of this component. As for the interpretation of the source code, it is not very difficult. As for the API of this component, you can directly view the corresponding methods after downloading the DLL file And attributes are not described in detail here.
Three. DotNetZip component usage examples:
The above is some analysis of the component, let's look at the example:
1. Compress ZIP file:
/// <summary>
/// Compress ZIP file
/// Support multiple files and directories, or multiple files and directories compressed together
/// </ summary>
/// <param name = "list"> File or directory collection 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 encoding to solve Chinese garbled characters 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
{
// The files in the directory are compressed to the root directory of Zip
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>
/// Unzip the ZIP file
/// </ summary>
/// <param name = "strZipPath"> ZIP file to be extracted </ param>
/// <param name = "strUnZipPath"> Uncompressed 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 encoding to solve Chinese garbled characters 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 of the specified input stream:
/// <summary>
/// get the ZIP compressed stream object for the specified input stream
/// </ 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. Get the ZIP decompressed stream object of the specified byte array:
/// <summary>
/// get the ZIP decompression stream object of the specified byte array
/// The current method is only applicable to a compressed package with only one compressed file, that is, only the first compressed file in the compressed package is taken in the method
/// </ 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);
// ms will be operated in the Extract method, and the Stream position must be reset to zero during subsequent use, otherwise no data will be read
// Perform a position zeroing action before returning this Stream object
decompressedStream.Position = 0;
}
}
}
catch (Exception ex)
{
throw new Exception (ex.Message);
}
return decompressedStream;
}
4. Summary:
The above are some examples of analysis and methods for DotNetZip components. As for whether this component is the best .NET compression component, this will not be evaluated. When selecting components, individuals first consider open source, followed by free, and finally consider efficiency and practicability. After all, some situations in China are clear to all developers (not to mention abroad because I do n’t know the situation abroad ). Customers need to reduce costs and components can be customized. However, I think that charging should be a trend. After all, all products require maintenance and development by personnel. There are deficiencies in the above blog posts, and I hope to correct them.