关于Unity Zip文件解压缩设计

unity中可能会使用到Zip文件解压缩的操作
例如:Unity Editor环境下,解压缩文件 到unity Assets 文件路劲下,再对解压缩文件进一步操作!

解压缩的方法
  1. DotNetZip
  2. 7-Zip
  3. 其他(无非调用解压缩内核)
DotNetZip示例
using AXClipperLib;
using Ionic.Zip;
using JUN.Xmpp.Iq.Privacy;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
using Action = System.Action;


public class DotNetZip : Singleton<DotNetZip>
{
    internal void UnpackPackage(string filename, string folder)
    {
        var ok = CheckZipIsOK(filename);//检查Zip文件是否正确
        string[] importExtensions = { ".obj", ".fbx", ".dae",".prefab" };//需要额外操作的文件 文件扩展名
        if (ok)
        {
            using (ZipFile file = new ZipFile(filename, Encoding.UTF8))
            {
                file.FlattenFoldersOnExtract = false;
                var status = new StringWriter();
                file.StatusMessageTextWriter = status;

                //记录需要额外操作文件的文件路径
                List<string> modelFileList = new List<string>();
                List<string> prefebFileList = new List<string>();
                //取出不需要操作的其他文件
                foreach (var entry in file.Entries)
                {
                    string name = entry.FileName.ToLowerInvariant();
                    if (!importExtensions.Any(e => { return name.EndsWith(e); }))
                        entry.Extract(folder, ExtractExistingFileAction.OverwriteSilently);
                }
                //取出需要操作的文件
                foreach (var entry in file.Entries)
                {
                    string name = entry.FileName.ToLowerInvariant();
                    if (name.EndsWith(".obj") || name.EndsWith(".fbx") || name.EndsWith(".dae"))
                    {
                        entry.Extract(folder, ExtractExistingFileAction.OverwriteSilently);
                        modelFileList.Add(folder + entry.FileName);
                    }
                    if (name.EndsWith(".prefab"))
                    {
                        entry.Extract(folder, ExtractExistingFileAction.OverwriteSilently);
                        prefebFileList.Add(folder + entry.FileName);
                    }
                }
                //文件预操作
                foreach (var item in modelFileList)
                {
                    //DoSomeThing(item);
                }

                foreach (var item in prefebFileList)
                {
                    //DoSomeThing(item);
                }
            }
        }
        //刷新
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    //解决关于文件命解压缩不区分大小写导致的覆盖问题!(好像没有差别)
    internal string UnpackPackageStream(string filename, string folder)
    {
        var ok = CheckZipIsOK(filename);//检查Zip文件是否正确
        string[] importExtensions = { ".obj", ".fbx", ".dae",".prefab" };//需要额外操作的文件 文件扩展名
        if (ok)
        {
            using (ZipInputStream stream = new ZipInputStream(filename))
            {
                var status = new StringWriter();
                ZipEntry entry;
                List<ZipEntry> modelZipEntryList = new List<ZipEntry>();
                List<ZipEntry> prefebZipEntryList = new List<ZipEntry>();
                while ((entry = stream.GetNextEntry()) != null)
                {
                    string name = entry.FileName.ToLowerInvariant();
                    if (!importExtraProceessExtensions.Any(e => { return name.EndsWith(e); }))
                    {
                        entry.Extract(folder, ExtractExistingFileAction.OverwriteSilently);
                    }

                    if (name.EndsWith(".prefab"))
                    {
                        entry.Extract(folder, ExtractExistingFileAction.OverwriteSilently);
                        prefebZipEntryList.Add(entry);
                    }
                    if (name.EndsWith(".obj"))
                    {
                        entry.Extract(folder, ExtractExistingFileAction.OverwriteSilently);
                        modelZipEntryList.Add(entry);

                    }

                }

                foreach (var e in modelZipEntryList)
                {
                    //DoSomeThing(item);
                }
                foreach (var e in prefebZipEntryList)
                {
                    //DoSomeThing(item);
                }
            }
        }
        else
        {
            UnityEngine.Debug.Log("Package is not OK, not processing");
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    string tempPath = "D:/Temp/Unpackage/";
    string tempUnityPath = "Assets/" + "Temp/";
    //解压缩到临时文件夹中先
    internal string UnpackPackageTemp(string filename, string folder)
    {
        DeleteAndCreateDirectory(tempPath);
        DeleteAndCreateDirectory(Path.GetFullPath(tempUnityPath));
        var ok = CheckZipIsOK(filename);
        string[] importExtensions = { ".obj", ".fbx", ".dae",".prefab" };//需要额外操作的文件 文件扩展名
        if (ok)
        {
            using (ZipFile file = new ZipFile(filename, Encoding.UTF8))
            {
                file.FlattenFoldersOnExtract = false;
                var status = new StringWriter();
                file.StatusMessageTextWriter = status;
                List<string> modelFileList = new List<string>();
                List<string> prefebFileList = new List<string>();

                //file ExtractAll 
                foreach (var entry in file.Entries)
                {
                    string name = entry.FileName.ToLowerInvariant();
                    if (!importExtraProceessExtensions.Any(e => { return name.EndsWith(e); }))
                        entry.Extract(tempPath, ExtractExistingFileAction.OverwriteSilently);
                }
                foreach (var entry in file.Entries)
                {
                    string name = entry.FileName.ToLowerInvariant();

                    if (name.EndsWith(".obj") || name.EndsWith(".fbx") || name.EndsWith(".dae"))
                    {
                        entry.Extract(tempPath, ExtractExistingFileAction.OverwriteSilently);
                        modelFileList.Add(tempPath + entry.FileName);
                    }
                    if (name.EndsWith(".prefab"))
                    {
                        entry.Extract(tempPath, ExtractExistingFileAction.OverwriteSilently);
                        prefebFileList.Add(tempPath + entry.FileName);

                    }
                }
                foreach (var item in prefebFileList)
                {
                    var tempPath;
                    //存在部分文件,需要在unity环境中,转换生成新类型文件,
                    //处理生成文件放置Unity 临时文件夹中。操作玩后,将生成新文件转移到外部临时文件夹目标位置。
                    TempUnityEditorCreator(item, tempPath, (string fileName, string oriengeFileName) =>
                    {
                        //Do some thing
                    });
                }


                AssetDatabase.Refresh();
                for (int i = 0; i < modelFileList.Count; i++) 处理生成文件
                    {
                    //存在部分文件,需要在unity 环境中修改参数
                    //转移到unity环境中
                    //操作
                    //新文件覆盖回去
                    TempUnityEditorCreator(modelFileList[i], (string filePath) =>
                    {
                        //Do some thing
                    });
                }
            }
        }
        else
        {
            UnityEngine.Debug.Log("Package is not OK, not processing");
        }
        AssetDatabase.DeleteAsset(folder);
        AssetDatabase.DeleteAsset(tempUnityPath);
        Directory.Move(tempPath, folder);//解压缩文件,移动到Unity路径下
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    private void DeleteAndCreateDirectory(string directoryPath, bool createNew = true)
    {
        if (string.IsNullOrEmpty(directoryPath))
        {
            return;
        }
        if (Directory.Exists(directoryPath))
        {
            try
            {
                Directory.Delete(directoryPath, true);
            }
            catch (Exception e)
            {
                UnityEngine.Debug.Log("Failed to delete the UnpackedData folder for " + e.Message + " Rename it to root folder to delete.");
                string name = DateTime.Now.ToFileTime().ToString();
                Directory.Move(directoryPath + "data\\Assets\\", "U:\\Tmp\\");
                Directory.Delete(directoryPath, true);
                try
                {
                    Directory.Delete("U:\\Tmp\\", true);
                }
                catch (Exception ex)
                {
                    UnityEngine.Debug.Log("Still Failed to delete the UnpackedData folder for " + ex.Message + " Rename it to aovid blocking.");
                    Directory.Move("U:\\Tmp\\", "U:\\Temp\\" + name + "\\");
                }
            }
        }
        if (createNew)
        {
            Directory.CreateDirectory(directoryPath);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    private void TempUnityEditorCreator(string fileName, string oriengeFileName, Action<string, string> active)
    {
        //do something to create file in unity directory
        var _fileName = Path.GetFileName(fileName);
        var _tempUnityFilePath = tempUnityPath + _fileName;
        active(fileName, _tempUnityFilePath);
        //move new create file to direction file
        File.Copy(_tempUnityFilePath, oriengeFileName, true);
    }

    private void TempUnityEditorCreator(string fileName, Action<string> active)
    {
        //copy file to unity directory 
        var _fileName = Path.GetFileName(fileName);
        var _tempUnityFilePath = tempUnityPath + _fileName;
        if (!File.Exists(_tempUnityFilePath))
        {
            File.Create(_tempUnityFilePath).Dispose();
        }
        File.Copy(fileName, _tempUnityFilePath, true);
        AssetDatabase.Refresh();
        //do some thing
        active(_tempUnityFilePath);
        //move back newer file
        File.Copy(_tempUnityFilePath, fileName, true);
    }
}
7-Zip 示例
在这里插入代码片
注意

一、 DotNetZip文件解压缩存在如下问题

  1. 解压缩文件名过长
  2. 解压缩强制文件名小写(存在文件相互覆盖)

二、Unity AssetDatabase 刷新问题

  1. 丢失关联问题
    当文件解压缩时,我们可能需要在AssetDatabase refresh前预操作
    当文件间存在相互引用关系,如果refresh后,再预操作,可能丢失关联!
    这就需要我们控制解压缩操作中仔细检查别AssetDatabase refresh操作
    但这很难
    提供个思路:
    我们先提前解压缩到Assets 外部的临时文件夹中,
    再对临时文件夹文件预操作,
    最后再移回Unity文件夹中

其他c#之如何使用太长/重复的路径处理解压缩 ZipFile