Unity 自动清理空文件夹

因为项目管控用的是Git,没法上传空文件夹。但是Unity又会对空文件夹生成相应的meta文件。导致Git提交的时候会提交这些meta文件。当项目中其他人拉下来的时候Unity又会将这些meta文件进行删除。一来二去冲突就来了。

使用CleanEmptyDir插件

插件挺好用的,就是美术还是不会去点进去自己清理一遍。所以,决定自己把它改成纯自动的。

代码实现

清理的核心代码还是用的插件的,然后把搜索部分开了个线程来跑。然后加了个自动清理的功能。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using UniRx;
using UnityEditor;
using UnityEngine;namespace AltProg.CleanEmptyDir
{[InitializeOnLoad]public class AutoCleanEmptyDir{/// <summary>///     资源地址/// </summary>private static readonly string dataPath;/// <summary>///     是否正在清理/// </summary>private static bool cleaning;/// <summary>///     自动清理触发事件/// </summary>private static readonly BoolReactiveProperty autoCleanDir = new BoolReactiveProperty();/// <summary>///     定时清理事件/// </summary>private static IDisposable timerClean;static AutoCleanEmptyDir(){dataPath = Application.dataPath;CheckAutoCleanDir();autoCleanDir.Subscribe(OnAutoClean);}/// <summary>///     自动清理启动函数/// </summary>private static void AutoClean(){if (cleaning) return;Debug.Log("检测到工程资源变动,开始检查是否有空文件夹。");Observable.Start(FindEmptyDir).ObserveOnMainThread().Where(_ =>{Debug.Log(_.Count > 0 ? $"检测到空文件夹{string.Join("\n", _)}" : "未检测到空文件夹。");return _.Count > 0;}).Subscribe(DeleteEmptyDir);}/// <summary>///     自动清理菜单函数/// </summary>[MenuItem("Assets/自动清理空文件夹")]public static void CheckAutoCleanDir(){autoCleanDir.Value = !autoCleanDir.Value;}/// <summary>///     当自动清理选项bool状态转换时/// </summary>private static void OnAutoClean(bool state){timerClean?.Dispose();timerClean = null;if (state){EditorApplication.projectChanged += AutoClean;Debug.Log("已启动自动清理空文件夹,将在工程资产变动时进行清理。");}else{EditorApplication.projectChanged -= AutoClean;timerClean = Observable.Timer(TimeSpan.FromHours(1)).Subscribe(_ => autoCleanDir.Value = true);Debug.Log("已关闭自动清理空文件夹,将在1小时后自动开启。");}Menu.SetChecked("Assets/自动清理空文件夹", state);}/// <summary>///     寻找空文件夹/// </summary>/// <returns>空文件夹列表</returns>private static List<DirectoryInfo> FindEmptyDir(){var newEmptyDirs = new List<DirectoryInfo>();WalkDirectoryTree(dataPath, (dirInfo, areSubDirsEmpty) =>{var isDirEmpty = areSubDirsEmpty && DirHasNoFile(dirInfo);if (isDirEmpty)newEmptyDirs.Add(dirInfo);return isDirEmpty;});return newEmptyDirs;}/// <summary>///     删除空文件夹/// </summary>/// <param name="infos">空文件夹列表</param>private static void DeleteEmptyDir(List<DirectoryInfo> infos){cleaning = true;foreach (var dirInfo in infos) AssetDatabase.MoveAssetToTrash(GetRelativePathFromCd(dirInfo.FullName));cleaning = false;}/// <summary>///     判断是否为空文件夹/// </summary>/// <param name="dirInfo">文件夹信息</param>/// <param name="areSubDirsEmpty">是否为空文件夹</param>private delegate bool IsEmptyDirectory(DirectoryInfo dirInfo, bool areSubDirsEmpty);/// <summary>///     遍历文件夹树/// </summary>/// <param name="rootPath">根文件路径</param>/// <param name="pred">判空方法</param>/// <returns></returns>private static bool WalkDirectoryTree(string rootPath, IsEmptyDirectory pred){var root = new DirectoryInfo(rootPath);//获取当前目录下的文件夹var subDirs = root.GetDirectories();//这个子文件是否为空var areSubDirsEmpty = true;//遍历子文件夹foreach (var dirInfo in subDirs)if (false == WalkDirectoryTree(dirInfo.FullName, pred))areSubDirsEmpty = false;var isRootEmpty = pred(root, areSubDirsEmpty);return isRootEmpty;}/// <summary>///     判断文件夹是否不存在文件/// </summary>/// <param name="dirInfo"></param>/// <returns></returns>private static bool DirHasNoFile(DirectoryInfo dirInfo){FileInfo[] files = null;try{files = dirInfo.GetFiles("*.*");files = files.Where(x => !IsMetaFile(x.Name)).ToArray();}catch (ThreadAbortException){}catch (Exception e){Debug.LogError(e.Message);}return files == null || files.Length == 0;}/// <summary>///     判断是否是Meta文件/// </summary>/// <param name="path"></param>/// <returns></returns>private static bool IsMetaFile(string path){return path.EndsWith(".meta");}private static string GetRelativePathFromCd(string filespec){return GetRelativePath(filespec, Directory.GetCurrentDirectory());}private static string GetRelativePath(string filespec, string folder){var pathUri = new Uri(filespec);// Folders must end in a slashif (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) folder += Path.DirectorySeparatorChar;var folderUri = new Uri(folder);return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));}}
}

注意事项

  1. 默认情况下当工程资源改动时就会触发清理。但是当美术烘焙场景生成光照贴图的时候会把原本的光照贴图删了,再生成。这中间有时候会先被当成空文件夹给清理掉。所以烘焙场景的时候最好先取消自动清理空文件夹的功能。
  2. 代码引用了UniRx库,不需要的可以自行修改。
  3. 有个弊端就是没法在Project窗口里直接新建文件夹了,要不就先暂时把功能关了,要不就直接去Windows文件管理窗口新建,然后把东西放进去。
  4. 关闭功能后,1小时后会自动勾选,具体的时间可以去代码里面进行调节。

Unity自动清理空文件夹相关推荐

  1. 服务器bat脚本删除空文件夹,windows批处理命令(1)——右键清理空文件夹

    日常学习工作免不了使用电脑,而作为一个强迫症,看到电脑中有空文件及其不爽: 再加上使用一些Git工具时含空文件不允许提交,因此就寻思着可不可以写一个脚本直接一键清理空文件夹. 最终实现的效果如下: 最 ...

  2. shell脚本--存储清理空文件夹

    注:此脚本用于存储处理空文件夹的内容,一般在ext3格式(或ext3版本之前的磁盘格式形式)的磁盘形式会出现文件夹满了之后无法在创建文件夹的情况!! 1.登录一台挂载存储的服务器,进入file文件夹 ...

  3. Linux如何彻底清理空文件夹

    博客主页:https://tomcat.blog.csdn.net 博主昵称:农民工老王 主要领域:Java.Linux.K8S 期待大家的关注

  4. 关于Linux系统清理/tmp/文件夹的清理时间等

    关于Linux系统清理/tmp/文件夹的清理时间等 本文转自http://www.opsers.org/base/clean-up-on-the-linux-system-tmp-folder-you ...

  5. unantu下的tmp文件夹_tmp是什么文件?Linux系统清理/tmp/文件夹的原理

    .tmp 文件大部分都是因为不正常关机.或死机后所留下的文件,这些临时的暂存盘,在你重新开机后,已经没有任何的用途,可以放心删除.大家在使用Windows操作系统的时候,可能会经常在C盘根目录发现一些 ...

  6. Unity 在编辑器菜单栏里添加清除空文件夹

    在 Assets/App/Editor 路径下新建 ClearEmptyFolder 文件夹,并在该文件夹下新建文件 EmptyFolderClear.cs using System.IO; usin ...

  7. w ndows7如何清理垃圾,windows7系统下在关机时如何自动清理垃圾文件

    如何让win7电脑关机时自动删除桌面文件夹?很多用户有习惯在关机的时候有时候都会选择清理一下系统的垃圾文件,不过会偶尔在关机的时候忘记了清理文件夹了,那么在windows7操作系统下有没有好的方法可以 ...

  8. 批量删除电脑或手机中的空文件夹

    目录 背景 国内外研究现状 背景 偶然看到python的OS库中有这样两个函数 os.rmdir() 删除空文件夹 remove dir os.mkdir() 新建文件夹 make dir 就想到能不 ...

  9. Java递归删除空文件夹

    import java.io.File;public class ClearFile {static int iFile = 0;public static void main(String[] ar ...

最新文章

  1. 开发工具之Android Studio快捷键
  2. 快速更换一个国内的yum源
  3. php parse url ctf,【SSRF】如何绕过filter_var(), preg_match() 和 parse_url()
  4. WebFlux响应式编程基础之 4 reactive stream 响应式流
  5. 【特征提取】基于matlab一帧语音共振峰提取【含Matlab源码 1768期】
  6. 微博上面好看的跳舞美女蛮多的,【Python爬虫】采集微博视频数据(附代完整代码)
  7. 【测试开发】Pytest—Html测试报告定制及封装
  8. VC++实现QQ消息群发
  9. Kubernetes实战[2]: 服务发现机制与Cluster DNS的安装(无CA认证版)
  10. 问题1:老毛桃一键装机打开后安装目录只显示u盘
  11. 微信是胖客户端瘦服务器,一款管理微信客户软件的系统体系结构设计?
  12. 记一次 .NET 某桌面奇侠游戏 非托管内存泄漏分析
  13. 已经解决globalsign证书导致淘宝京东等chrome safari无法访问
  14. 学习:SharePoint Caml Filter with Muli-values Lookup field
  15. 【排序】一次查找两元素
  16. 华为2023年研发实习生招聘
  17. 设置标点符号不在行首
  18. 菜鸟的Unity自学日志10 音频
  19. Linux is内存管理,【原创】(七)Linux内存管理
  20. 判断推理——类比推理

热门文章

  1. QQ游戏: 四国军棋和中国象棋客户端失败
  2. MSP430定时器应用
  3. c语言军棋源代码,VC++(MSSQL数据库)军棋游戏大厅联网对战#(源代码+可
  4. 违禁词查询 麦谈帮API数据接口
  5. OFBiz电商实战视频教程
  6. 台达PLC如何实现远程上下载程序及远程更新参数
  7. 三角函数相关公式_正弦余弦
  8. 手机市场已饱和?好产品总会有市场 乐视之后还有谁?
  9. android 烟雾传感器,烟雾传感器扫盲,现在知道还不晚
  10. 记一次乐视随身看T50固件telnet的root密码寻找流程