首页 > 编程 > .NET > 正文

详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)

2020-01-17 22:32:32
字体:
来源:转载
供稿:网友

前面介绍了六种.NET组件,其中有一种组件是写文件的压缩和解压,现在介绍另一种文件的解压缩组件SharpZipLib。在这个组件介绍系列中,只为简单的介绍组件的背景和简单的应用,读者在阅读时可以结合官网的相关介绍和在本地实际操作。

相关的组件功能非常强大,在笔者的介绍中只是提及到简单的应用,需要了解更多的操作和特性,可以根据官网介绍,或者查看DLL文件的相关类和方法,以此来扩展相关的业务需要。

SharpZipLib是一个完全在C#中为.NET平台编写的Zip,GZip,Tar和BZip2库。

一.SharpZipLib组件概述:

ziplib(SharpZipLib,以前的NZipLib)是一个完全在C#为.NET平台编写的Zip,GZip,Tar和BZip2库。它实现为一个程序集(可安装在GAC中),因此可以轻松地集成到其他项目(任何.NET语言)中。 #ziplib的创建者这样说:“我已经将zip库移植到C#,因为我需要gzip / zip压缩,我不想使用libzip.dll或类似的东西我想要的所有在纯C#“。

SharpZipLib官网提供的下载操作:.NET 1.1,.NET 2.0(3.5,4.0),.NET CF 1.0,.NET CF 2.0的装配:下载237 KB,源代码和示例下载708 KB;源代码和示例下载708 KB;帮助文件下载1208 KB;

SharpZipLib是在GPL下发布,遵守开源协议。

二.SharpZipLib核心类和方法介绍:

以上简单的介绍了SharpZipLib组件的相关背景,现在具体看一下该组件的相关核心类和方法:

  

1.ZipOutputStream类PutNextEntry():

public void PutNextEntry(ZipEntry entry){  bool hasCrc;  if (entry == null)  {    throw new ArgumentNullException("entry");  }  if (this.entries == null)  {    throw new InvalidOperationException("ZipOutputStream was finished");  }  if (this.curEntry != null)  {    this.CloseEntry();  }  if (this.entries.Count == 0x7fffffff)  {    throw new ZipException("Too many entries for Zip file");  }  CompressionMethod compressionMethod = entry.CompressionMethod;  int defaultCompressionLevel = this.defaultCompressionLevel;  entry.Flags &= 0x800;  this.patchEntryHeader = false;  if (entry.Size == 0L)  {    entry.CompressedSize = entry.Size;    entry.Crc = 0L;    compressionMethod = CompressionMethod.Stored;    hasCrc = true;  }  else  {    hasCrc = (entry.Size >= 0L) && entry.HasCrc;    if (compressionMethod == CompressionMethod.Stored)    {      if (!hasCrc)      {        if (!base.CanPatchEntries)        {          compressionMethod = CompressionMethod.Deflated;          defaultCompressionLevel = 0;        }      }      else      {        entry.CompressedSize = entry.Size;        hasCrc = entry.HasCrc;      }    }  }  if (!hasCrc)  {    if (!base.CanPatchEntries)    {      entry.Flags |= 8;    }    else    {      this.patchEntryHeader = true;    }  }  if (base.Password != null)  {    entry.IsCrypted = true;    if (entry.Crc < 0L)    {      entry.Flags |= 8;    }  }  entry.Offset = this.offset;  entry.CompressionMethod = compressionMethod;  this.curMethod = compressionMethod;  this.sizePatchPos = -1L;  if ((this.useZip64_ == UseZip64.On) || ((entry.Size < 0L) && (this.useZip64_ == UseZip64.Dynamic)))  {    entry.ForceZip64();  }  this.WriteLeInt(0x4034b50);  this.WriteLeShort(entry.Version);  this.WriteLeShort(entry.Flags);  this.WriteLeShort((byte) entry.CompressionMethodForHeader);  this.WriteLeInt((int) entry.DosTime);  if (hasCrc)  {    this.WriteLeInt((int) entry.Crc);    if (entry.LocalHeaderRequiresZip64)    {      this.WriteLeInt(-1);      this.WriteLeInt(-1);    }    else    {      this.WriteLeInt(entry.IsCrypted ? (((int) entry.CompressedSize) + 12) : ((int) entry.CompressedSize));      this.WriteLeInt((int) entry.Size);    }  }  else  {    if (this.patchEntryHeader)    {      this.crcPatchPos = base.baseOutputStream_.Position;    }    this.WriteLeInt(0);    if (this.patchEntryHeader)    {      this.sizePatchPos = base.baseOutputStream_.Position;    }    if (entry.LocalHeaderRequiresZip64 || this.patchEntryHeader)    {      this.WriteLeInt(-1);      this.WriteLeInt(-1);    }    else    {      this.WriteLeInt(0);      this.WriteLeInt(0);    }  }  byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);  if (buffer.Length > 0xffff)  {    throw new ZipException("Entry name too long.");  }  ZipExtraData extraData = new ZipExtraData(entry.ExtraData);  if (entry.LocalHeaderRequiresZip64)  {    extraData.StartNewEntry();    if (hasCrc)    {      extraData.AddLeLong(entry.Size);      extraData.AddLeLong(entry.CompressedSize);    }    else    {      extraData.AddLeLong(-1L);      extraData.AddLeLong(-1L);    }    extraData.AddNewEntry(1);    if (!extraData.Find(1))    {      throw new ZipException("Internal error cant find extra data");    }    if (this.patchEntryHeader)    {      this.sizePatchPos = extraData.CurrentReadIndex;    }  }  else  {    extraData.Delete(1);  }  if (entry.AESKeySize > 0)  {    AddExtraDataAES(entry, extraData);  }  byte[] entryData = extraData.GetEntryData();  this.WriteLeShort(buffer.Length);  this.WriteLeShort(entryData.Length);  if (buffer.Length > 0)  {    base.baseOutputStream_.Write(buffer, 0, buffer.Length);  }  if (entry.LocalHeaderRequiresZip64 && this.patchEntryHeader)  {    this.sizePatchPos += base.baseOutputStream_.Position;  }  if (entryData.Length > 0)  {    base.baseOutputStream_.Write(entryData, 0, entryData.Length);  }  this.offset += (30 + buffer.Length) + entryData.Length;  if (entry.AESKeySize > 0)  {    this.offset += entry.AESOverheadSize;  }  this.curEntry = entry;  this.crc.Reset();  if (compressionMethod == CompressionMethod.Deflated)  {    base.deflater_.Reset();    base.deflater_.SetLevel(defaultCompressionLevel);  }  this.size = 0L;  if (entry.IsCrypted)  {    if (entry.AESKeySize > 0)    {      this.WriteAESHeader(entry);    }    else if (entry.Crc < 0L)    {      this.WriteEncryptionHeader(entry.DosTime << 0x10);    }    else    {      this.WriteEncryptionHeader(entry.Crc);    }  }}

2.ZipOutputStream类Finish():

public override void Finish(){  if (this.entries != null)  {    if (this.curEntry != null)    {      this.CloseEntry();    }    long count = this.entries.Count;    long sizeEntries = 0L;    foreach (ZipEntry entry in this.entries)    {      this.WriteLeInt(0x2014b50);      this.WriteLeShort(0x33);      this.WriteLeShort(entry.Version);      this.WriteLeShort(entry.Flags);      this.WriteLeShort((short) entry.CompressionMethodForHeader);      this.WriteLeInt((int) entry.DosTime);      this.WriteLeInt((int) entry.Crc);      if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL))      {        this.WriteLeInt(-1);      }      else      {        this.WriteLeInt((int) entry.CompressedSize);      }      if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL))      {        this.WriteLeInt(-1);      }      else      {        this.WriteLeInt((int) entry.Size);      }      byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);      if (buffer.Length > 0xffff)      {        throw new ZipException("Name too long.");      }      ZipExtraData extraData = new ZipExtraData(entry.ExtraData);      if (entry.CentralHeaderRequiresZip64)      {        extraData.StartNewEntry();        if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL))        {          extraData.AddLeLong(entry.Size);        }        if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL))        {          extraData.AddLeLong(entry.CompressedSize);        }        if (entry.Offset >= 0xffffffffL)        {          extraData.AddLeLong(entry.Offset);        }        extraData.AddNewEntry(1);      }      else      {        extraData.Delete(1);      }      if (entry.AESKeySize > 0)      {        AddExtraDataAES(entry, extraData);      }      byte[] entryData = extraData.GetEntryData();      byte[] buffer3 = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Flags, entry.Comment) : new byte[0];      if (buffer3.Length > 0xffff)      {        throw new ZipException("Comment too long.");      }      this.WriteLeShort(buffer.Length);      this.WriteLeShort(entryData.Length);      this.WriteLeShort(buffer3.Length);      this.WriteLeShort(0);      this.WriteLeShort(0);      if (entry.ExternalFileAttributes != -1)      {        this.WriteLeInt(entry.ExternalFileAttributes);      }      else if (entry.IsDirectory)      {        this.WriteLeInt(0x10);      }      else      {        this.WriteLeInt(0);      }      if (entry.Offset >= 0xffffffffL)      {        this.WriteLeInt(-1);      }      else      {        this.WriteLeInt((int) entry.Offset);      }      if (buffer.Length > 0)      {        base.baseOutputStream_.Write(buffer, 0, buffer.Length);      }      if (entryData.Length > 0)      {        base.baseOutputStream_.Write(entryData, 0, entryData.Length);      }      if (buffer3.Length > 0)      {        base.baseOutputStream_.Write(buffer3, 0, buffer3.Length);      }      sizeEntries += ((0x2e + buffer.Length) + entryData.Length) + buffer3.Length;    }    using (ZipHelperStream stream = new ZipHelperStream(base.baseOutputStream_))    {      stream.WriteEndOfCentralDirectory(count, sizeEntries, this.offset, this.zipComment);    }    this.entries = null;  }}

 3.ZipEntry类Clone():

public object Clone(){  ZipEntry entry = (ZipEntry) base.MemberwiseClone();  if (this.extra != null)  {    entry.extra = new byte[this.extra.Length];    Array.Copy(this.extra, 0, entry.extra, 0, this.extra.Length);  }  return entry;}

 4.ZipOutputStream类Write():

public override void Write(byte[] buffer, int offset, int count){  if (this.curEntry == null)  {    throw new InvalidOperationException("No open entry.");  }  if (buffer == null)  {    throw new ArgumentNullException("buffer");  }  if (offset < 0)  {    throw new ArgumentOutOfRangeException("offset", "Cannot be negative");  }  if (count < 0)  {    throw new ArgumentOutOfRangeException("count", "Cannot be negative");  }  if ((buffer.Length - offset) < count)  {    throw new ArgumentException("Invalid offset/count combination");  }  this.crc.Update(buffer, offset, count);  this.size += count;  switch (this.curMethod)  {    case CompressionMethod.Stored:      if (base.Password != null)      {        this.CopyAndEncrypt(buffer, offset, count);      }      else      {        base.baseOutputStream_.Write(buffer, offset, count);      }      break;    case CompressionMethod.Deflated:      base.Write(buffer, offset, count);      break;  }}

三.SharpZipLib实例:

  1.压缩单个文件:

   

   /// <summary>    /// 压缩单个文件    /// </summary>    /// <param name="fileToZip">要压缩的文件</param>    /// <param name="zipedFile">压缩后的文件</param>    /// <param name="compressionLevel">压缩等级</param>    /// <param name="blockSize">每次写入大小</param>    public static void ZipFile(string fileToZip, string zipedFile, int compressionLevel, int blockSize)    {      if (string.IsNullOrEmpty(fileToZip))      {        throw new ArgumentNullException(fileToZip);      }      if (string.IsNullOrEmpty(zipedFile))      {        throw new ArgumentNullException(zipedFile);      }      if (!File.Exists(fileToZip))      {        throw new FileNotFoundException("指定要压缩的文件: " + fileToZip + " 不存在!");      }      try      {        using (var zipFile = File.Create(zipedFile))        {          using (var zipStream = new ZipOutputStream(zipFile))          {            using (var streamToZip = new FileStream(fileToZip, FileMode.Open, FileAccess.Read))            {              var fileName = fileToZip.Substring(fileToZip.LastIndexOf("//", StringComparison.Ordinal) + 1);              var zipEntry = new ZipEntry(fileName);              zipStream.PutNextEntry(zipEntry);              zipStream.SetLevel(compressionLevel);              var buffer = new byte[blockSize];              try              {                int sizeRead;                do                {                  sizeRead = streamToZip.Read(buffer, 0, buffer.Length);                  zipStream.Write(buffer, 0, sizeRead);                }                while (sizeRead > 0);              }              catch (Exception ex)              {                throw new Exception(ex.Message);              }              streamToZip.Close();            }            zipStream.Finish();            zipStream.Close();          }          zipFile.Close();        }      }      catch (IOException ioex)      {        throw new IOException(ioex.Message);      }      catch (Exception ex)      {        throw new Exception(ex.Message);      }    }

 2. 压缩单个文件:

    /// <summary>    /// 压缩单个文件    /// </summary>    /// <param name="fileToZip">要进行压缩的文件名</param>    /// <param name="zipedFile">压缩后生成的压缩文件名</param>    public static void ZipFile(string fileToZip, string zipedFile)    {      if (string.IsNullOrEmpty(fileToZip))      {        throw new ArgumentException(fileToZip);      }      if (string.IsNullOrEmpty(zipedFile))      {        throw new ArgumentException(zipedFile);      }      if (!File.Exists(fileToZip))      {        throw new FileNotFoundException("指定要压缩的文件: " + fileToZip + " 不存在!");      }      try      {        using (var fs = File.OpenRead(fileToZip))        {          var buffer = new byte[fs.Length];          fs.Read(buffer, 0, buffer.Length);          fs.Close();          using (var zipFile = File.Create(zipedFile))          {            using (var zipStream = new ZipOutputStream(zipFile))            {              var fileName = fileToZip.Substring(fileToZip.LastIndexOf("//", StringComparison.Ordinal) + 1);              var zipEntry = new ZipEntry(fileName);              zipStream.PutNextEntry(zipEntry);              zipStream.SetLevel(5);              zipStream.Write(buffer, 0, buffer.Length);              zipStream.Finish();              zipStream.Close();            }          }        }      }      catch (IOException ioex)      {        throw new IOException(ioex.Message);      }      catch (Exception ex)      {        throw new Exception(ex.Message);      }    }

3.压缩多层目录:

   /// <summary>    /// 压缩多层目录    /// </summary>    /// <param name="strDirectory">目录</param>    /// <param name="zipedFile">压缩文件</param>    public static void ZipFileDirectory(string strDirectory, string zipedFile)    {      if (string.IsNullOrEmpty(strDirectory))      {        throw new ArgumentException(strDirectory);      }      if (string.IsNullOrEmpty(zipedFile))      {        throw new ArgumentException(zipedFile);      }      using (var zipFile = File.Create(zipedFile))      {        using (var s = new ZipOutputStream(zipFile))        {          ZipSetp(strDirectory, s, "");        }      }    }

4.递归遍历目录:

    /// <summary>    /// 递归遍历目录    /// </summary>    /// <param name="strDirectory">目录</param>    /// <param name="s">ZipOutputStream对象</param>    /// <param name="parentPath">父路径</param>    private static void ZipSetp(string strDirectory, ZipOutputStream s, string parentPath)    {      if (strDirectory[strDirectory.Length - 1] != Path.DirectorySeparatorChar)      {        strDirectory += Path.DirectorySeparatorChar;      }      var crc = new Crc32();      var filenames = Directory.GetFileSystemEntries(strDirectory);      try      {        // 遍历所有的文件和目录        foreach (var file in filenames)        {          // 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件          if (Directory.Exists(file))          {            var pPath = parentPath;            pPath += file.Substring(file.LastIndexOf("//", StringComparison.Ordinal) + 1);            pPath += "//";            ZipSetp(file, s, pPath);          }          // 否则直接压缩文件          else          {            //打开压缩文件            using (var fs = File.OpenRead(file))            {              var buffer = new byte[fs.Length];              fs.Read(buffer, 0, buffer.Length);              var fileName = parentPath + file.Substring(file.LastIndexOf("//", StringComparison.Ordinal) + 1);              var entry = new ZipEntry(fileName)              {                DateTime = DateTime.Now,                Size = fs.Length              };              fs.Close();              crc.Reset();              crc.Update(buffer);              entry.Crc = crc.Value;              s.PutNextEntry(entry);              s.Write(buffer, 0, buffer.Length);            }          }        }      }      catch (IOException ioex)      {        throw new IOException(ioex.Message);      }      catch (Exception ex)      {        throw new Exception(ex.Message);      }    }

5.解压缩一个 zip 文件: 

    /// <summary>    /// 解压缩一个 zip 文件。    /// </summary>    /// <param name="zipedFile">The ziped file.</param>    /// <param name="strDirectory">The STR directory.</param>    /// <param name="password">zip 文件的密码。</param>    /// <param name="overWrite">是否覆盖已存在的文件。</param>    public void UnZip(string zipedFile, string strDirectory, string password, bool overWrite)    {      if (string.IsNullOrEmpty(zipedFile))      {        throw new ArgumentException(zipedFile);      }      if (string.IsNullOrEmpty(strDirectory))      {        throw new ArgumentException(strDirectory);      }      if (string.IsNullOrEmpty(password))      {        throw new ArgumentException(password);      }      if (strDirectory == "")      {        strDirectory = Directory.GetCurrentDirectory();      }      if (!strDirectory.EndsWith("//"))      {        strDirectory = strDirectory + "//";      }      try      {        using (var s = new ZipInputStream(File.OpenRead(zipedFile)))        {          s.Password = password;          ZipEntry theEntry;          while ((theEntry = s.GetNextEntry()) != null)          {            var directoryName = string.Empty;            var pathToZip = theEntry.Name;            if (pathToZip != "")            {              directoryName = Path.GetDirectoryName(pathToZip) + "//";            }            var fileName = Path.GetFileName(pathToZip);            Directory.CreateDirectory(strDirectory + directoryName);            if (fileName == "") continue;            if ((!File.Exists(strDirectory + directoryName + fileName) || !overWrite) &&              (File.Exists(strDirectory + directoryName + fileName))) continue;            using (var streamWriter = File.Create(strDirectory + directoryName + fileName))            {              var data = new byte[2048];              while (true)              {                var size = s.Read(data, 0, data.Length);                if (size > 0)                  streamWriter.Write(data, 0, size);                else                  break;              }              streamWriter.Close();            }          }          s.Close();        }      }      catch (IOException ioex)      {        throw new IOException(ioex.Message);      }      catch (Exception ex)      {        throw new Exception(ex.Message);      }    }

四.总结:

以上是对SharpZipLib组件的相关介绍,本文的讲解上比较的浅显,如果需要深入的学习可以进入官网进行详细的学习。组件的功能是很强大的,如何在项目中使用组件,完成我们在项目中需要实现的功能,这就是对每个开发者提出了要求,需要我们仔细的去考虑。

任何学习都需要我们自己去探索和思考,对于一个开发者来说,最重要的就是思考,因为在我们的职业生涯中,没有什么的重要性能够超过思考。如果有不足之处还望各位读者包含,并留言指正。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表