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


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

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

    .NET组件介绍系列:

        一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)http://www.cnblogs.com/pengze0902/p/6122311.html

        高效而稳定的企业级.NET Office 组件Spire(.NET组件介绍之二)http://www.cnblogs.com/pengze0902/p/6125570.html

        最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)http://www.cnblogs.com/pengze0902/p/6124659.html

        免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)http://www.cnblogs.com/pengze0902/p/6134506.html

        免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)http://www.cnblogs.com/pengze0902/p/6128558.html

        免费高效实用的Excel操作组件NPOI(.NET组件介绍之六)http://www.cnblogs.com/pengze0902/p/6150070.html

       免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)http://www.cnblogs.com/pengze0902/p/6159497.html

  • 相关阅读:
    Nginx的配置详解
    马拉车算法
    C++ 智能指针(shared_ptr/weak_ptr)原理分析
    大小端(内存、寄存器、CPU)
    printf函数输出字符串乱码问题
    ArcGIS中应用Expressions标注(Label)之二—使用外部数据库中数据标注要素
    Cisco Aironet ap3g1/ap3g2 8.5版本胖AP固件网页配置教程
    Golang mapstructure
    NDB 和 InnoDB 的不同
    高质量:Makefile
  • 原文地址:https://www.cnblogs.com/pengze0902/p/6159497.html
Copyright © 2020-2023  润新知