最近研究了一下使用U3D解压压缩包,需要引入ICSharpCode.SharpZipLib.dll,稍后会添加下载链接。

方法一:

本示例是在打开PC端的.zip文件,因为是在本地的文件,所以没有下载代码,但是添加了一个解压进度条,下面直接贴代码:

using UnityEngine;
using System.Collections;
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;
using UnityEngine.UI;

public class ZipUtility : MonoBehaviour
{
    [SerializeField] private Slider slider;
    [SerializeField] private Text sliderText;
    [SerializeField] private string zipPath;
    [SerializeField] private string outPath;
    /// <summary>
    /// 解压缩按钮
    /// </summary>
    [SerializeField] private Button UnZipBtn;


    // Use this for initialization
    void Start()
    {
        UnZipBtn.onClick.AddListener(UnZip);
    }
    
    /// <summary>
    /// 解压Zip
    /// </summary>
    public void UnZip()
    {
        StartCoroutine(UnzipWithPath());
    }

    private int doneCount;
    private int indicatorStep = 1;
    private float currentComSize;

    /// <summary>
    /// 解压缩
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public IEnumerator UnzipWithPath()
    {
        FileInfo fileInfo = new FileInfo(zipPath);
        slider.gameObject.SetActive(true);
        Debug.Log("Length:" + fileInfo.Length);

        //ZipEntry:文件条目 就是该目录下所有的文件列表(也就是所有文件的路径)
        ZipEntry zip = null;
        //输入的所有的文件流都是存储在这里面的
        //ZipInputStream zipInStream = null;
        //读取文件流到zipInputStream
        ZipInputStream zipInStream = new ZipInputStream(File.OpenRead(zipPath));
        //循环读取Zip目录下的所有文件
        while ((zip = zipInStream.GetNextEntry()) != null)
        {
            UnzipFile(zip, zipInStream);

            currentComSize += zip.CompressedSize;
            float sliderValue = (currentComSize / fileInfo.Length) * 100.0f;
            doneCount++;
            Debug.Log("进度:" + sliderValue);
            sliderText.text = "当前已解压" + doneCount + "个文件,已解压" + sliderValue.ToString("F2") + "%";
            slider.value = currentComSize / fileInfo.Length;
            if (doneCount % indicatorStep == 0)
            {
                yield return new WaitForEndOfFrame();
            }
        }
        try
        {
            zipInStream.Close();
        }
        catch (Exception ex)
        {
            Debug.Log("UnZip Error");
            throw ex;
        }

        Debug.Log("解压完成:" + zipPath);
        slider.gameObject.SetActive(false);
    }
    public void UnzipFile(ZipEntry zip, ZipInputStream zipInStream)
    {
        try
        {
            //文件名
            string fileName = Path.GetFileName(zip.Name);
            //文件地址
            string filePath = Path.Combine(outPath, zip.Name);
            //文件夹名
            string directoryName = Path.GetDirectoryName(filePath);
            // 创建压缩文件中文件的位置
            if (directoryName.Length > 0)
            {
                Directory.CreateDirectory(directoryName);
            }

            //文件名不为空
            if (!string.IsNullOrEmpty(zip.Name))
            {
                FileStream fs = null;
                //当前文件夹下有该文件  删掉  重新创建
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                fs = File.Create(filePath);
                int size = 2048;
                byte[] data = new byte[2048];
                //每次读取2MB  直到把这个内容读完
                while (true)
                {
                    size = zipInStream.Read(data, 0, data.Length);
                    //小于0, 也就读完了当前的流
                    if (size > 0)
                    {
                        fs.Write(data, 0, size);
                    }
                    else
                    {
                        break;
                    }
                }
                fs.Close();
            }
        }
        catch (Exception e)
        {
            throw new Exception();
        }
    }
}

ICSharpCode.SharpZipLib.dll下载链接:下载链接 提取码:5ow0

踩坑备注

打包PC端测试的时候报错:

Unity 文件浏览 打开unity文件_Unity 文件浏览


解决方案:

将I18N.DLL 和 I18N.CJK.DLL 从Unity安装目录(Editor\Data\Mono\lib\mono\unity 和 Editor\Data\Mono\lib\mono\2.0 两个目录下都存在)拷贝到项目目录的Assets目录下,然后重新编译出包,可正常运行。

方法二:

.NET4.5以上版本支持:

using System.IO.Compression;

//zipPath:zip文件的路径
//outPath:解压路径
 ZipFile.ExtractToDirectory(zipPath, outPath);
注意:

这两种方法均不支持双层文件夹,方法一的使用有部分局限性,如果文件夹层级太多可能会判断有误不能解压。

Unity 文件浏览 打开unity文件_压缩文件_02


Unity 文件浏览 打开unity文件_Unity 文件浏览_03

方法三:

压缩文件和文件夹、对文件和文件夹进行解压:

using System.IO;
using UnityEngine;
using ICSharpCode.SharpZipLib.Zip;
`
public static class ZipHelper
    {
        #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);
            /*
             * ICSharpCode.SharpZipLib.Zip.ZipConstants.DefaultCodePage默认为437(美国/加拿大英语),
             * 如果被解压的文件不是437编码将报CodePage 437 not supported错误。
             */
#if UNITY_STANDALONE_WIN
         ZipConstants.DefaultCodePage =System.Text.Encoding.UTF8.CodePage;           
#endif

            // 解压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;
        }
    }``