打包出来的热更文件,如果每次都要全部上传到CDN文件服务器,不进耗费时间长,还浪费流量。
所以让AI写了个简单的文件比较工具类,然后修改了一下可用。记录一下。
路径可自行更改。校验算法这里使用的是MD5,如果使用SHA256校验,时间会长达1分钟,MD5只有5秒左右。一般用MD5即可。同步拷贝的写法时间太长,改为异步拷贝的写法,时间减半,只需30秒和3秒。(项目的热更文件67个,总大小在700M左右)
代码如下,放到Assets/Editor/路径下即可。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEditor;
/// <summary>
/// 比较热更文件的差异 拷贝到另一个文件夹
/// </summary>
public class HotfixComparerAsync
{
#if UNITY_ANDROID
static string SourceFolder = Application.dataPath + "/../ServerData/Android"; // 源文件夹路径
static string TargetFolder = Application.dataPath + "/../ServerData/Android_server"; // 目标文件夹路径
static string OutputFolder = Application.dataPath + "/../ServerData/Android_hotfix"; // 输出文件夹路径,存放复制的文件
#endif
#if UNITY_IOS
static string SourceFolder = Application.dataPath + "/../ServerData/iOS"; // 源文件夹路径
static string TargetFolder = Application.dataPath + "/../ServerData/iOS_server"; // 目标文件夹路径
static string OutputFolder = Application.dataPath + "/../ServerData/iOS_hotfix"; // 输出文件夹路径,存放复制的文件
#endif
#if UNITY_STANDALONE_WIN
static string SourceFolder = Application.dataPath + "/../ServerData/StandaloneWindows64"; // 源文件夹路径
static string TargetFolder = Application.dataPath + "/../ServerData/StandaloneWindows64_server"; // 目标文件夹路径
static string OutputFolder = Application.dataPath + "/../ServerData/StandaloneWindows64_hotfix"; // 输出文件夹路径,存放复制的文件
#endif
[MenuItem("Tools/比较并拷贝热更文件Async")]
public static void CompareAndCopyFiles()
{
DateTime startTime = DateTime.Now;
if (!Directory.Exists(OutputFolder))
{
Directory.CreateDirectory(OutputFolder);
}
var sourceFiles = new HashSet<string>(Directory.GetFiles(SourceFolder, "*.*", SearchOption.AllDirectories));
var targetFilesHashes = new Dictionary<string, string>();
foreach (var file in Directory.GetFiles(TargetFolder, "*.*", SearchOption.AllDirectories))
{
string relativePath = MakeRelativePath(file, TargetFolder);
targetFilesHashes[relativePath] = FileHash(file);
}
var tasks = new List<Task>();
foreach (var sourceFile in sourceFiles)
{
string relativePath = MakeRelativePath(sourceFile, SourceFolder);
tasks.Add(Task.Run(() => ProcessFile(sourceFile, relativePath, targetFilesHashes)));
}
Task.WhenAll(tasks.ToArray()).Wait();
TimeSpan diff = DateTime.Now - startTime;
Debug.Log($"比较完成耗费:{diff.Minutes}分{diff.Seconds}秒");
}
private static void ProcessFile(string sourceFile, string relativePath, Dictionary<string, string> targetFilesHashes)
{
if (targetFilesHashes.ContainsKey(relativePath))
{
string hash = FileHash(sourceFile);
if (targetFilesHashes[relativePath] != hash)
{
CopyFile(sourceFile, Path.Combine(OutputFolder, relativePath));
}
}
else
{
CopyFile(sourceFile, Path.Combine(OutputFolder, relativePath));
}
}
private static string MakeRelativePath(string path, string rootDirectory)
{
return path.Substring(rootDirectory.Length + 1);
}
private static string FileHash(string file)
{
using (var stream = File.OpenRead(file))
{
using (var hash = MD5.Create())
{
byte[] hashBytes = hash.ComputeHash(stream);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
}
}
}
private static void CopyFile(string sourceFile, string targetFile)
{
//File.Copy(sourceFile, targetFile, true);
// 获取目标文件的目录路径
string targetDirectory = Path.GetDirectoryName(targetFile);
// 如果目标目录不存在,则创建它
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
try
{
// 尝试复制文件
File.Copy(sourceFile, targetFile, true);
}
catch (Exception e)
{
// 处理可能的异常
Debug.LogError($"Failed to copy file from {sourceFile} to {targetFile}. Error: {e.Message}");
}
}
}