Location>code7788 >text

NET Compressing/Uncompressing Files

Popularity:191 ℃/2024-09-06 21:43:11

NET decompression/compression of zip files. Although decompression is not a core technology, but compression performance and progress of processing or need to pay attention to, for the use of more zip open source components to verify , to provide you with the technology selection!

Currently know the common technology solutions are, SharpZipLib and DotNetZip, the following we introduce the use and performance of the following

Recommended if you need to handle simple ZIP compression and decompression tasks and don't need advanced features. NET standard library, does not require additional installation of third-party libraries, and will be updated as the .

Look at the code implementation:

 1     /// <summary>
 2     /// Decompressing Zip Files
 3     /// </summary>
 4     /// <param name="filePath">zip file path</param>
 5     /// <param name="outputFolder">decompression directory</param>
 6     /// <returns></returns>
 7     public static void Decompress(string filePath, string outputFolder)
 8     {
 9         (filePath, outputFolder);
10     }
11 
12     /// <summary>
13     /// Compress into a Zip file
14     /// </summary>
15     /// <param name="sourceFolder">file directory</param>
16     /// <param name="zipFile">zip file path</param>
17     /// <param name="includeFolder">Whether to include the parent directory of the file (i.e. the sourceFolder itself)</param>
18     /// <returns></returns>
19     public static void Compress(string sourceFolder, string zipFile, bool includeFolder = true)
20     {
21         (sourceFolder, zipFile, , includeFolder);
22     }

The advantages are obvious, the API is simple and easy to understand, suitable for simple file compression and decompression operations. Of course, the functions provided are rather basic, lacking some advanced features, such as volume compression and encryption, and also can not provide detailed progress of the operation.

Let's test decompression performance. Find a zip file."Firmware and Installation Packages Needed for Smart Micro Factory Production.zip"The file size is 847M, and it has the following structure with files and folders:

Decompression time: 8484ms. zip the decompressed folder again, time: 28672ms.
So, the simpler business scenarios can be used directly with this solution. You can put this solution in the company's common basic technology components.

SharpZipLib

Supports a variety of compression formats (such as ZIP, TAR, GZIP, BZIP2, etc.), and provides advanced features such as encryption, split-volume compression and so on.icsharpcode/SharpZipLib: #ziplib is a Zip, GZip, Tar and BZip2 library written entirely in C# for the .NET platform. ()

API design usability, to meet more complex customization needs. Many partners in the community are using it, with a long history of development and high component stability.

After referencing the Nuget package SharpZipLib, unzip the zip file.

Get the size of the compressed file, here Size is the size before compression, there is a property CompressedSize compressed size:

 1         public static long GetZipFileTotalSize(string zipPath)
 2         {
 3             long totalSize = 0;
 4             using FileStream fileStream = (zipPath);
 5             using ZipInputStream zipStream = new ZipInputStream(fileStream);
 6             while (() is { } zipEntry)
 7             {
 8                 totalSize += ;
 9             }
10 
11             return totalSize;
12         }

Extract the Zip file:

 1       /// <summary>
 2       /// Decompressing Zip Files
 3       /// </summary>
 4       /// <param name="zipFile">zip file path</param>
 5       /// <param name="outputFolder">decompression directory</param>
 6       /// <param name="cancellationToken">Cancel operation</param>
 7       /// <param name="progressChanged">Decompression progress callbacks</param>
 8       /// <returns></returns>
 9       public static async Task UnZipAsync(string zipFile, string outputFolder,
10           CancellationToken cancellationToken = default, Action<ZipProgress> progressChanged = null)
11       {
12           if (!(zipFile))
13           {
14               throw new InvalidOperationException($"file not exist,{zipFile}");
15           }
16           var decompressLength = GetZipFileTotalSize(zipFile);
17           using FileStream fileStream = (zipFile);
18           await (() =>
19           {
20               using ZipInputStream zipStream = new ZipInputStream(fileStream);
21               long completedSize = 0;
22               while (() is { } zipEntry)
23               {
24                   if (cancellationToken != default && )
25                   {
26                       ();
27                   }
28 
29                   if ()
30                   {
31                       string folder = (outputFolder, );
32                       EnsureFolder(folder);
33                   }
34                   else if ()
35                   {
36                       var operatingSize = completedSize;
37                       var zipEntryName = ;
38                       string fullEntryPath = (outputFolder, zipEntryName);
39                       string dirPath = (fullEntryPath);
40                       EnsureFolder(dirPath);
41                       //Unzipped data
42                       long singleFileSize = WriteUnzipDataToFile(zipStream, fullEntryPath, partialFileSize =>
43                       {
44                           if (progressChanged == null)
45                           {
46                               return;
47                           }
48                           long currentSize = operatingSize + partialFileSize;
49                           (new ZipProgress(currentSize, decompressLength, zipEntryName));
50                       });
51                       completedSize += singleFileSize;
52                   }
53               }
54           }, cancellationToken);
55       }

Decompression progress can feedback detailed file writing progress value. In addition, there is a folder judgment processing, which also supports empty folders

Zip compression, get all folders/subfolders, all files, add to ZipFile and save:

 1       /// <summary>
 2       /// zip file
 3       /// </summary>
 4       /// <param name="toZipDirectory">Folders to be compressed</param>
 5       /// <param name="destZipPath">Zip file save path</param>
 6       /// <returns></returns>
 7       public static bool Zip(string toZipDirectory, string destZipPath)
 8       {
 9           if (string.IsNullOrEmpty(destZipPath))
10           {
11               throw new ArgumentNullException(nameof(destZipPath));
12           }
13           if (!().EndsWith(".ZIP"))
14           {
15               throw new ArgumentException("The save path is not a ZIP extension", nameof(destZipPath));
16           }
17           if (!(toZipDirectory))
18           {
19               throw new ArgumentException("The folder to be compressed does not exist", nameof(toZipDirectory));
20           }
21 
22           var dirs = (toZipDirectory, "*", )
23               .Select(dir => (toZipDirectory, dir));
24           var files = (toZipDirectory, "*", ).ToArray();
25           var destFiles = (file => (toZipDirectory, file)).ToArray();
26           if ((destZipPath))
27           {
28               (destZipPath);
29           }
30           using (ZipFile zipFile = (destZipPath))
31           {
32               ();
33               foreach (var dir in dirs)
34               {
35                   (dir);
36               }
37               for (int i = 0; i < ; i++)
38               {
39                   (files[i], destFiles[i]);
40               }
41               ();
42           }
43           return true;
44       }

It is worth mentioning that, if you need to specify the file name as well as the file path within the Zip archive, you can enter the corresponding post-compression path definition at the time of the file, noting that it refers to the relative path within the zip archive:

 1       /// <summary>Compresses the specified file into the corresponding zip file</summary>
 2       /// <param name="files">List of file paths to be compressed (absolute paths)</param>
 3       /// <param name="destFiles">The list of file paths corresponding to the compressed paths, i.e., the paths of the files in the compressed package after compression</param>
 4       /// <param name="destZipPath">Zip file save path</param>
 5       public static bool Zip(List<string> files, List<string> destFiles, string destZipPath)
 6       {
 7           if ( != )
 8           {
 9               throw new ArgumentException($"{nameof(files)} does not match {nameof(destFiles)} the number of file lists");
10           }
11           if (string.IsNullOrEmpty(destZipPath))
12               throw new ArgumentNullException(nameof(destZipPath));
13           using (ZipFile zipFile = (destZipPath))
14           {
15               ();
16               for (int i = 0; i < ; i++)
17               {
18                   (files[i], destFiles[i]);
19               }
20               ();
21           }
22           return true;
23       }

SharpZipLib is feature-rich, but if you look at the demo code above, the interface is a bit complicated and the learning curve is high!
Again, let's do the above test, unzip the same zip file, unzipping takes time20719msTime-consuming compression102109ms。。。

DotNetZip

Look again.DotNetZip, this relative to SharpZipLib, the API is designed to be more friendly and easy to use. The official website ishaf/(), it stopped being maintained.... The author recommends everyone to use it! Well first ignore this, although it is no longer actively maintained, but the stability, performance is really good, the following gives you a list of use demo and performance tests

The Zip file is unzipped:

 1     /// <summary>
 2     /// Decompressing Zip Files
 3     /// </summary>
 4     /// <param name="zipFile">zip file path</param>
 5     /// <param name="outputFolder">decompression directory</param>
 6     /// <param name="password">cryptographic</param>
 7     /// <param name="progressChanged">Decompression progress callbacks</param>
 8     /// <returns></returns>
 9     public static void UnZip(string zipFile, string outputFolder, string password, Action<ZipProgress> progressChanged)
10     {
11         if (!(zipFile)) throw new InvalidOperationException($"file not exist,{zipFile}");
12         //Get the size of the unzipped file
13         var totalZipSize = GetZipFileSize(zipFile);
14         long completedSize = 0L;
15         using (var zip = (zipFile))
16         {
17              = password;
18              += (s, e) =>
19             {
20                 if ( == ZipProgressEventType.Extracting_EntryBytesWritten)
21                 {
22                     var fileName = ;
23                     if ( < )
24                     {
25                         //Progress in single file decompression
26                         var operatingSize = completedSize + ;
27                         progressChanged?.Invoke(new ZipProgress(operatingSize, totalZipSize, fileName));
28                     }
29                     else
30                     {
31                         //Progress towards complete decompression of a single file
32                         completedSize += ;
33                         progressChanged?.Invoke(new ZipProgress(completedSize, totalZipSize, fileName));
34                     }
35                 }
36             };
37             (outputFolder);
38         }
39     }

Here we get the size of the compressed file, which corresponds to SharpZipLib's above, and is taken as

Very human to provide ExtractProgress event progress, we take the Extracting_EntryBytesWritten type, you can get the details of the progress. Look at the code above to see how the progress is handled

Because the feedback is detailed byte write progress, the intervals are very short.... .1ms can give you several bursts of progress, especially with large files:

So you need to limit the callback Action trigger, you can add a timer to limit the progress of a single file callback, such as 100ms within the maximum trigger once, the following is the optimized code:

 1     /// <summary>
 2     /// Decompressing Zip Files
 3     /// </summary>
 4     /// <param name="zipFile">zip file path</param>
 5     /// <param name="outputFolder">decompression directory</param>
 6     /// <param name="password">cryptographic</param>
 7     /// <param name="progressChanged">Decompression progress callbacks</param>
 8     /// <returns></returns>
 9     public static void UnZip(string zipFile, string outputFolder, string password,
10         Action<ZipProgress> progressChanged)
11     {
12         if (!(zipFile)) throw new InvalidOperationException($"file not exist,{zipFile}");
13         //Get the size of the unzipped file
14         var totalZipSize = GetZipFileSize(zipFile);
15         long completedSize = 0L;
16         using (var zip = (zipFile))
17         {
18              = password;
19             var lastProgressTick = ;
20              += (s, e) =>
21             {
22                 if ( == ZipProgressEventType.Extracting_EntryBytesWritten)
23                 {
24                     var fileName = ;
25                     if ( < )
26                     {
27                         // Individual file decompression changes, limiting intervals to trigger decompression events
28                         if ( - lastProgressTick < ProgressEventTick)
29                         {
30                             return;
31                         }
32                         lastProgressTick = ;
33                         //Progress in single file decompression
34                         var operatingSize = completedSize + ;
35                         progressChanged?.Invoke(new ZipProgress(operatingSize, totalZipSize, fileName));
36                     }
37                     else
38                     {
39                         //reset timer
40                         lastProgressTick = ;
41                         //Progress towards complete decompression of a single file
42                         completedSize += ;
43                         progressChanged?.Invoke(new ZipProgress(completedSize, totalZipSize, fileName));
44                     }
45                 }
46             };
47             (outputFolder);
48         }
49     }

Take a look at Zip compression again:

 1     public static void Zip(string sourceFolder, string destZipFile, string password,
 2         Action<ZipProgress> zipProgressAction)
 3     {
 4         if (string.IsNullOrEmpty(destZipFile)) throw new ArgumentNullException(nameof(destZipFile));
 5         if (!().EndsWith(".ZIP")) throw new ArgumentException("The save path is not a Zip file", destZipFile);
 6         if ((destZipFile)) (destZipFile);
 7 
 8         using (var zipFile = new ZipFile())
 9         {
10             // Setting up the compression progress event handler
11              += (sender, e) =>
12             {
13                 if ( == ZipProgressEventType.Saving_AfterWriteEntry)
14                     zipProgressAction?.Invoke(new ZipProgress(, , ));
15             };
16             (sourceFolder);
17              = password;
18             (destZipFile);
19         }
20     }

If you do not take into account the encryption, compression progress, DotNetZip zip file compression only a few lines of code, so it is quite easy to learn to use, start fast!

Test the decompression performance, unzip11907msTime-consuming compression16282msThe data speaks for itself.

List the comparison of these three options in a table:

So if you need to handle simple ZIP compression and decompression tasks and don't need advanced features, it is recommended to use the

need to consider decompression performance.Recommended DotNetZip. As for the situation of stopping maintenance can be suddenly, there are bugs we can maintain this component code in the company or github