美文网首页csharpunityunity3D技术分享
Unity中使用C#实现Zip包的压缩与解压

Unity中使用C#实现Zip包的压缩与解压

作者: acb348921872 | 来源:发表于2017-03-11 20:31 被阅读4989次

    使用SharpZipLib库,下载地址为:http://icsharpcode.github.io/SharpZipLib/

    /******************************************************
    * DESCRIPTION: Zip包的压缩与解压
    *
    *     Copyright (c) 2017, 谭伟俊 (TanWeijun)
    *     All rights reserved
    *
    * CREATED: 2017.03.11, 08:37, CST
    ******************************************************/
    
    using System.IO;
    using System.Collections;
    using UnityEngine;
    using ICSharpCode.SharpZipLib.Zip;
    
    public static class ZipUtility
    {
        #region ZipCallback
        public abstract class ZipCallback
        {
            /// <summary>
            /// 压缩单个文件或文件夹前执行的回调
            /// </summary>
            /// <param name="_entry"></param>
            /// <returns>如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹</returns>
            public virtual bool OnPreZip(ZipEntry _entry)
            {
                return true;
            }
    
            /// <summary>
            /// 压缩单个文件或文件夹后执行的回调
            /// </summary>
            /// <param name="_entry"></param>
            public virtual void OnPostZip(ZipEntry _entry) {}
    
            /// <summary>
            /// 压缩执行完毕后的回调
            /// </summary>
            /// <param name="_result">true表示压缩成功,false表示压缩失败</param>
            public virtual void OnFinished(bool _result) {}
        }
        #endregion
    
        #region UnzipCallback
        public abstract class UnzipCallback
        {
            /// <summary>
            /// 解压单个文件或文件夹前执行的回调
            /// </summary>
            /// <param name="_entry"></param>
            /// <returns>如果返回true,则压缩文件或文件夹,反之则不压缩文件或文件夹</returns>
            public virtual bool OnPreUnzip(ZipEntry _entry)
            {
                return true;
            }
    
            /// <summary>
            /// 解压单个文件或文件夹后执行的回调
            /// </summary>
            /// <param name="_entry"></param>
            public virtual void OnPostUnzip(ZipEntry _entry) {}
    
            /// <summary>
            /// 解压执行完毕后的回调
            /// </summary>
            /// <param name="_result">true表示解压成功,false表示解压失败</param>
            public virtual void OnFinished(bool _result) {}
        }
        #endregion
    
        /// <summary>
        /// 压缩文件和文件夹
        /// </summary>
        /// <param name="_fileOrDirectoryArray">文件夹路径和文件名</param>
        /// <param name="_outputPathName">压缩后的输出路径文件名</param>
        /// <param name="_password">压缩密码</param>
        /// <param name="_zipCallback">ZipCallback对象,负责回调</param>
        /// <returns></returns>
        public static bool Zip( string[] _fileOrDirectoryArray, string _outputPathName, string _password = null, ZipCallback _zipCallback = null)
        {
            if ((null == _fileOrDirectoryArray) || string.IsNullOrEmpty(_outputPathName))
            {
                if (null != _zipCallback)
                    _zipCallback.OnFinished(false);
    
                return false;
            }
    
            ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(_outputPathName));
            zipOutputStream.SetLevel(6);    // 压缩质量和压缩速度的平衡点
            if (!string.IsNullOrEmpty(_password))
                zipOutputStream.Password = _password;
    
            for (int index = 0; index < _fileOrDirectoryArray.Length; ++index)
            {
                bool result = false;
                string fileOrDirectory = _fileOrDirectoryArray[index];
                if (Directory.Exists(fileOrDirectory))
                    result = ZipDirectory(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
                else if (File.Exists(fileOrDirectory))
                    result = ZipFile(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
    
                if (!result)
                {
                    if (null != _zipCallback)
                        _zipCallback.OnFinished(false);
    
                    return false;
                }
            }
    
            zipOutputStream.Finish();
            zipOutputStream.Close();
    
            if (null != _zipCallback)
                _zipCallback.OnFinished(true);
    
            return true;
        }
    
        /// <summary>
        /// 解压Zip包
        /// </summary>
        /// <param name="_filePathName">Zip包的文件路径名</param>
        /// <param name="_outputPath">解压输出路径</param>
        /// <param name="_password">解压密码</param>
        /// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
        /// <returns></returns>
        public static bool UnzipFile(string _filePathName, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
        {
            if (string.IsNullOrEmpty(_filePathName) || string.IsNullOrEmpty(_outputPath))
            {
                if (null != _unzipCallback)
                    _unzipCallback.OnFinished(false);
    
                return false;
            }
    
            try
            {
                return UnzipFile(File.OpenRead(_filePathName), _outputPath, _password, _unzipCallback);
            }
            catch (System.Exception _e)
            {
                Debug.LogError("[ZipUtility.UnzipFile]: " + _e.ToString());
    
                if (null != _unzipCallback)
                    _unzipCallback.OnFinished(false);
    
                return false;
            }
        }
    
        /// <summary>
        /// 解压Zip包
        /// </summary>
        /// <param name="_fileBytes">Zip包字节数组</param>
        /// <param name="_outputPath">解压输出路径</param>
        /// <param name="_password">解压密码</param>
        /// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
        /// <returns></returns>
        public static bool UnzipFile(byte[] _fileBytes, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
        {
            if ((null == _fileBytes) || string.IsNullOrEmpty(_outputPath))
            {
                if (null != _unzipCallback)
                    _unzipCallback.OnFinished(false);
    
                return false;
            }
    
            bool result = UnzipFile(new MemoryStream(_fileBytes), _outputPath, _password, _unzipCallback);
            if (!result)
            {
                if (null != _unzipCallback)
                    _unzipCallback.OnFinished(false);
            }
    
            return result;
        }
    
        /// <summary>
        /// 解压Zip包
        /// </summary>
        /// <param name="_inputStream">Zip包输入流</param>
        /// <param name="_outputPath">解压输出路径</param>
        /// <param name="_password">解压密码</param>
        /// <param name="_unzipCallback">UnzipCallback对象,负责回调</param>
        /// <returns></returns>
        public static bool UnzipFile(Stream _inputStream, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
        {
            if ((null == _inputStream) || string.IsNullOrEmpty(_outputPath))
            {
                if (null != _unzipCallback)
                    _unzipCallback.OnFinished(false);
    
                return false;
            }
    
            // 创建文件目录
            if (!Directory.Exists(_outputPath))
                Directory.CreateDirectory(_outputPath);
    
            // 解压Zip包
            ZipEntry entry = null;
            using (ZipInputStream zipInputStream = new ZipInputStream(_inputStream))
            {
                if (!string.IsNullOrEmpty(_password))
                    zipInputStream.Password = _password;
    
                while (null != (entry = zipInputStream.GetNextEntry()))
                {
                    if (string.IsNullOrEmpty(entry.Name))
                        continue;
    
                    if ((null != _unzipCallback) && !_unzipCallback.OnPreUnzip(entry))
                        continue;   // 过滤
    
                    string filePathName = Path.Combine(_outputPath, entry.Name);
    
                    // 创建文件目录
                    if (entry.IsDirectory)
                    {
                        Directory.CreateDirectory(filePathName);
                        continue;
                    }
    
                    // 写入文件
                    try
                    {
                        using (FileStream fileStream = File.Create(filePathName))
                        {
                            byte[] bytes = new byte[1024];
                            while (true)
                            {
                                int count = zipInputStream.Read(bytes, 0, bytes.Length);
                                if (count > 0)
                                    fileStream.Write(bytes, 0, count);
                                else
                                {
                                    if (null != _unzipCallback)
                                        _unzipCallback.OnPostUnzip(entry);
    
                                    break;
                                }
                            }
                        }
                    }
                    catch (System.Exception _e)
                    {
                        Debug.LogError("[ZipUtility.UnzipFile]: " + _e.ToString());
    
                        if (null != _unzipCallback)
                            _unzipCallback.OnFinished(false);
    
                        return false;
                    }
                }
            }
    
            if (null != _unzipCallback)
                _unzipCallback.OnFinished(true);
    
            return true;
        }
    
        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="_filePathName">文件路径名</param>
        /// <param name="_parentRelPath">要压缩的文件的父相对文件夹</param>
        /// <param name="_zipOutputStream">压缩输出流</param>
        /// <param name="_zipCallback">ZipCallback对象,负责回调</param>
        /// <returns></returns>
        private static bool ZipFile(string _filePathName, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
        {
            //Crc32 crc32 = new Crc32();
            ZipEntry entry = null;
            FileStream fileStream = null;
            try
            {
                string entryName = _parentRelPath + '/' + Path.GetFileName(_filePathName);
                entry = new ZipEntry(entryName);
                entry.DateTime = System.DateTime.Now;
    
                if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
                    return true;    // 过滤
    
                fileStream = File.OpenRead(_filePathName);
                byte[] buffer = new byte[fileStream.Length];
                fileStream.Read(buffer, 0, buffer.Length);
                fileStream.Close();
    
                entry.Size = buffer.Length;
    
                //crc32.Reset();
                //crc32.Update(buffer);
                //entry.Crc = crc32.Value;
    
                _zipOutputStream.PutNextEntry(entry);
                _zipOutputStream.Write(buffer, 0, buffer.Length);
            }
            catch (System.Exception _e)
            {
                Debug.LogError("[ZipUtility.ZipFile]: " + _e.ToString());
                return false;
            }
            finally
            {
                if (null != fileStream)
                {
                    fileStream.Close();
                    fileStream.Dispose();
                }
            }
    
            if (null != _zipCallback)
                _zipCallback.OnPostZip(entry);
    
            return true;
        }
    
        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="_path">要压缩的文件夹</param>
        /// <param name="_parentRelPath">要压缩的文件夹的父相对文件夹</param>
        /// <param name="_zipOutputStream">压缩输出流</param>
        /// <param name="_zipCallback">ZipCallback对象,负责回调</param>
        /// <returns></returns>
        private static bool ZipDirectory(string _path, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
        {
            ZipEntry entry = null;
            try
            {
                string entryName = Path.Combine(_parentRelPath, Path.GetFileName(_path) + '/');
                entry = new ZipEntry(entryName);
                entry.DateTime = System.DateTime.Now;
                entry.Size = 0;
    
                if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
                    return true;    // 过滤
    
                _zipOutputStream.PutNextEntry(entry);
                _zipOutputStream.Flush();
    
                string[] files = Directory.GetFiles(_path);
                for (int index = 0; index < files.Length; ++index)
                    ZipFile(files[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback);
            }
            catch (System.Exception _e)
            {
                Debug.LogError("[ZipUtility.ZipDirectory]: " + _e.ToString());
                return false;
            }
    
            string[] directories = Directory.GetDirectories(_path);
            for (int index = 0; index < directories.Length; ++index)
            {
                if (!ZipDirectory(directories[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback))
                    return false;
            }
    
            if (null != _zipCallback)
                _zipCallback.OnPostZip(entry);
    
            return true;
        }
    }
    

    相关文章

      网友评论

      • 4edba6836fe0:private void WaitCallBackHandler(object AsyncState) {
        AsyncStateObj state = (AsyncStateObj)AsyncState;
        ZipEntry entry = state.ZEntry;
        ZipUnCompressCB unzcb = state.UCompress;
        Stream entryStream = state.EntryStream;
        string filePathName = state.FilePath;

        FileStream fileStream = state.FStream;
        byte[] bytes = new byte[ZipUtility.DEFAULT_BYTE_LEN];
        while(true) {
        int readSize = entryStream.Read(bytes,0,bytes.Length);
        Debug.Log(string.Format("解压文件:{0}, size:{1}",entry.Name,bytes.Length));
        if(readSize > 0) {
        fileStream.Write(bytes,0,bytes.Length);
        }
        else {
        if(unzcb != null) {
        unzcb.OnPostUnzip(entry);
        }

        if(unzcb.UnZipCount == unzcb.FileCount) {
        res = true;
        isDone = true;
        }
        break;
        }
        }

        fileStream.Close();
        fileStream.Dispose();
        }

        public ZipUnCompressThread(ZipFile zipFile, string _outputPath, ZipUnCompressCB unzcb = null) {
        int worker,io;
        ThreadPool.GetMaxThreads(out worker,out io);
        Debug.Log(string.Format("1、CLR线程池默认最大线程数据,工作者线程数:{0},IO线程数:{1}",worker,io));
        unzcb.FileCount = (int)zipFile.Count;

        for (int i = 0; i < zipFile.Count; i++) {
        ZipEntry entry = zipFile[i];
        string filePathName = PathUtil.Combine(_outputPath, entry.Name); //_outputPath + entry.Name;

        if(entry.IsFile) {
        Stream entryStream = zipFile.GetInputStream(i);

        if(File.Exists(filePathName)) {
        File.Delete(filePathName);
        };
        FileStream fileStream = File.Open(filePathName,FileMode.OpenOrCreate);

        AsyncStateObj state = new AsyncStateObj {
        ZEntry = entry,
        UCompress = unzcb,
        FilePath = filePathName,
        EntryStream = entryStream,
        FStream = fileStream
        };
        ThreadPool.QueueUserWorkItem(WaitCallBackHandler,state);
        }
        else if(entry.IsDirectory) {
        if(!Directory.Exists(filePathName)) {
        Directory.CreateDirectory(filePathName);
        }
        if(unzcb != null) {
        unzcb.OnPostUnzip(entry);
        }
        }
        }
        }
      • 4edba6836fe0:我解压一个24M的文件,要4分多钟,其中最大的文件是11M。。。这解压算法还没网络下载快。。。。 多线程解压 。 如果单线程。。。。呵呵lone time . 如果解压小文件没什么感觉。 大文件就。。。。。。。哎。
      • jc_5313:使用zip()方法对同一个文件Test.txt(内容为空)生成多个zip文件(如Test1.zip,Test2.zip等等),按说源文件都是Test.txt,得到的Test1.zip和Test2.zip应该是完全一样的,但实际上在计算2个zip的md5时,发现二者不同,请问博主是为什么呢?
      • cy9Lyz:这几行的功能是什么呀,为啥给屏蔽了。
        //Crc32 crc32 = new Crc32();
        //crc32.Reset();
        //crc32.Update(buffer);
        //entry.Crc = crc32.Value;
        acb348921872:用于CRC校验,我没有用到,所以就注释掉了 :)
      • 蝣来蝣去:hi 你好,看了下 好像全部是同步操作,在手机上 如果包体过大的话,会特别卡吧
        acb348921872:@蝣来蝣去 apk我们使用了OBB机制,OBB其实就是我们自己生成的zip包,目录在app对应的OBB路径,由google规定。
        蝣来蝣去:@EnigmaJJ :+1: 嗯 好的,我把改成了异步主线程调用的,但是有个问题,你们的zip包 是在streamingAsset目录下的吗 ?
        acb348921872:开启另外一个线程进行压缩和解压操作,这也是设计ZipCallback类的意义:在压缩和解压过程中可以回调主线程的代码 :smile:
      • 石皮_32a9:想问问,跨平台是否测试过?安卓、 苹果 是否通过。。
        acb348921872:@yockapple 提供的算法是跨平台的,安卓和苹果上都已发布使用的项目
        yockapple:同问,现在unity跨平台解压都怎么处理

      本文标题:Unity中使用C#实现Zip包的压缩与解压

      本文链接:https://www.haomeiwen.com/subject/sbjzgttx.html