Unity编辑器小工具——文件查重(MD5)
算法思想:
在Unity中,每一个不同资源、文件所生成MD5码是不同的,但是相同文件,路径不同、文件名不同的同一类文件的MD5码是相同的,所以可以通过生成每个文件的MD5来判断文件是否是重复的。
具体脚本代码如下:
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEditor;
using System.Security.Cryptography;
using System;
using System.Linq;
public class FindMD : MonoBehaviour {
string[] files;
[MenuItem("Assets/Find Files MD5")]
public static void Find()
{
int flag = 0;
string[] files = Directory.GetFiles("Assets/", "*.*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; i++)
{
if (files[i].EndsWith(".meta"))
{
continue;
}
//加载进度条
EditorUtility.DisplayCancelableProgressBar("匹配资源中", files[i], ((float)i / (float)files.Length));
for (int j = 0; j < files.Length; j++)
{
if (files[j].EndsWith(".meta"))
{
continue;
}
if (i != j && getFileMD5(files[i]) == getFileMD5(files[j]))
{
Debug.LogError(files[i] + " and " + files[j] + "have the same md5");
flag = 1;
}
}
}
//清除进度条
EditorUtility.ClearProgressBar();
if (flag == 0)
{
Debug.Log("No files are equal");
}
}
public static string getFileMD5(string filePath)
{
//将文件路径转化为文件流
FileStream fs = new FileStream(filePath, FileMode.Open);
byte[] data = new byte[(int)fs.Length];
//读文件
fs.Read(data, 0, (int)fs.Length);
fs.Close();
//通过MD5接口生成MD5码(获得的是Hash一个字节数组)MD5加密
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(data);
//将获得的Hash字节数组转换为字符串
string fileMD5 = "";
foreach (byte b in result)
{
fileMD5 += Convert.ToString(b, 16);
}
//fs.Close();
return fileMD5;
}
}
注意要点:
1. 在Unity下,每个文件都有对应的meta文件,但是对于文件查重来说并没有什么实际的用途,所以在文件读取对比时可以跳过
2. 在进行meta文件筛选时,有两种办法,一种如脚本中一样,在要比较md5码前,判断是否为meta文件。另一种为在Directory.GetFiles() 时,通过拉曼达表达式来进行筛选,但是在使用拉曼达表达式时,还要使用foreach循环进行查找,所以放弃了后种方法
3. 由于使用了双层for循环,所以查找速率较低,后通过如下脚本进行了改进
改进脚本如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System.Security.Cryptography;
using System;
using System.Linq;
public class FindMD_2 : MonoBehaviour {
string[] files;
[MenuItem("Assets/Find Files MD5")]
public static void Find()
{
int flag = 0;
Dictionary<string, string> MDdic = new Dictionary<string, string>();
string[] files = Directory.GetFiles("Assets/", "*.*", SearchOption.AllDirectories);
string file_2 = "";
for (int i = 0; i < files.Length; i++)
{
string filemd5 = getFileMD5(files[i]);
if (files[i].EndsWith(".meta"))
{
continue;
}
//加载进度条
EditorUtility.DisplayCancelableProgressBar("匹配资源中", files[i], ((float)i / (float)files.Length));
if (MDdic.ContainsValue(filemd5))
{
foreach (string key in MDdic.Keys)
{
if (MDdic[key].Equals(filemd5))
{
file_2 = key;
}
}
Debug.LogError(files[i] + " and " + file_2.ToString() + "have the same md5");
}
else
{
MDdic.Add(files[i], filemd5);
}
}
if (flag == 0)
{
Debug.Log("No files are equal");
}
}
public static string getFileMD5(string filePath)
{
//将文件路径转化为文件流
FileStream fs = new FileStream(filePath, FileMode.Open);
byte[] data = new byte[(int)fs.Length];
//读文件
fs.Read(data, 0, (int)fs.Length);
fs.Close();
//通过MD5接口生成MD5码(获得的是Hash一个字节数组)MD5加密
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(data);
//将获得的Hash字节数组转换为字符串
string fileMD5 = "";
foreach (byte b in result)
{
fileMD5 += Convert.ToString(b, 16);
}
//fs.Close();
return fileMD5;
}
}