using System; using System.IO; using UnityEngine; using System.Text; using System.Collections; using UnityEngine.Networking; using System.Threading.Tasks; using System.Threading; using System.Collections.Generic; namespace XRTool.Util { /// /// 文件工具类 /// 下载,写入文件,断点续传,边下边存 /// 遍历,拷贝文件 /// 获取文件的MD5等 /// public class DataFileUtil { /// /// 预估的写入文件的速度,与真实速度无关,仅仅是模拟评估,预计写入用时 /// public const float WriteSpeed = 1024 * 1024 * 150f; ///// ///// 写入缓存的大小,如果越小,可能会引起卡顿(频繁访问数据) ///// //public const int CacheSave = 1024 * 1024 * 2; /// /// 图片格式 /// public static string[] TexturesType = new string[] { "BMP", "EXR", "GIF", "HDR", "IFF", "JPG", "PICT", "PNG", "PSD", "TGA", "TIFF" }; /// /// 视频格式 /// public static string[] MoviesType = new string[] { "MOV", "MPG", "MP4", "AVI", "ASF" }; /// /// 音频格式 /// public static string[] AudiosType = new string[] { "ACC", "AIFF", "IT", "MOD", "MPEG", "OGGVORBIS", "S3M", "AIF", "WAV", "MP3", "OGG","XM","XMA","VAG","AUDIOQUEUE" }; public static int maxTryCount = 5; /// /// 下载数据到本地,并将下载的数据返回给到上层应用 /// 此下载仅应用于可缓存的资源,图片文本等下载,大文件的下载请使用断点下载 /// /// /// /// /// /// /// public static IEnumerator DownLoadData(string url, string path, Action completeData, DownloadHandler hander = null, Action downLoadProcess=null, bool isAsync = false) { bool isDowning = true; UnityWebRequest web = null; //DownloadHandlerTexture yield return RequestDownData(url, (string error, UnityWebRequest req) => { ///下载成功后开始拷贝数据到本地 if (string.IsNullOrEmpty(error)) { ///同步存储方法 if (!isAsync) { SaveDataToFile(path, req.downloadHandler.data); downLoadProcess?.Invoke(req.downloadHandler.data.Length, 1); completeData?.Invoke(path, req); return; } else { web = req; ///此时,已下载到内存中,但是仍未缓存至内存中,内存数据可用 completeData?.Invoke(null, req); } } else { ///下载出错 completeData?.Invoke(null, null); //UnityLog.Instance.LogError(error); } isDowning = false; }, hander, (float allLeng, float process) => { ///下载的进度,1/1.2,给存储留进度条显示,约等于0.89 downLoadProcess?.Invoke(allLeng, process / 1.12f); }); ///等待下载完成,此下载是下载到内存中 while (isDowning) { yield return 0; } if (isAsync && web != null) { //completeData?.Invoke(true, data); yield return SaveDataToFile(path, web.downloadHandler.data, (float saveProcess) => { ///更新存储文件的进度 downLoadProcess?.Invoke(web.downloadHandler.data.Length, saveProcess * 0.1f + 0.9f); }, (bool isSuccess, string filePath) => { completeData?.Invoke(filePath, web); }); } web.Dispose(); } //public static IEnumerator DownLoadData(string url, string path, Action completeData, // DownloadHandler hander = null, Action downLoadProcess = null, bool isAsync = false) //{ // bool isDowning = true; // UnityWebRequest web = null; // //DownloadHandlerTexture // yield return RequestDownData(url, (string error, UnityWebRequest req) => // { // ///下载成功后开始拷贝数据到本地 // if (string.IsNullOrEmpty(error)) // { // ///同步存储方法 // if (!isAsync) // { // SaveDataToFile(path, req.downloadHandler.data); // downLoadProcess?.Invoke(req.downloadHandler.data.Length, 1); // completeData?.Invoke(path, req); // return; // } // else // { // web = req; // ///此时,已下载到内存中,但是仍未缓存至内存中,内存数据可用 // completeData?.Invoke(null, req); // } // } // else // { // ///下载出错 // completeData?.Invoke(null, null); // //UnityLog.Instance.LogError(error); // } // isDowning = false; // }, hander, (float allLeng, float process) => // { // ///下载的进度,1/1.2,给存储留进度条显示,约等于0.89 // downLoadProcess?.Invoke(allLeng, process / 1.12f); // }); // ///等待下载完成,此下载是下载到内存中 // while (isDowning) // { // yield return 0; // } // if (isAsync && web != null) // { // //completeData?.Invoke(true, data); // yield return SaveDataToFile(path, web.downloadHandler.data, (float saveProcess) => // { // ///更新存储文件的进度 // downLoadProcess?.Invoke(web.downloadHandler.data.Length, saveProcess * 0.1f + 0.9f); // }, (bool isSuccess, string filePath) => // { // completeData?.Invoke(filePath, web); // }); // } //} /// /// 请求后台数据接口 /// /// public static IEnumerator RequestData(string url, Action reqComplete, bool isPost = true, Dictionary header = null, Dictionary form = null, Action complete = null) { ///表单 using (UnityWebRequest web = isPost ? UnityWebRequest.Post(url, form) : UnityWebRequest.Get(url)) { if (header != null) { foreach (var item in header) { web.SetRequestHeader(item.Key, item.Value); } } yield return web.SendWebRequest(); if (web.isNetworkError || web.isHttpError) { UnityLog.Instance.LogError(web.error); reqComplete?.Invoke(null); complete?.Invoke(); yield break; } else { reqComplete?.Invoke(web.downloadHandler.text); complete?.Invoke(); } } } /// /// 获取资源的大小 /// /// /// /// public static IEnumerator GetDataSize(string url, Action getLen) { var headRequest = UnityWebRequest.Head(url); yield return headRequest.SendWebRequest(); getLen?.Invoke(long.Parse(headRequest.GetResponseHeader("Content-Length"))); headRequest.Dispose(); } /// /// 异步下载,此下载不再判断文件是否存在,直接走下载方法 /// 请在传值时先对DownInfo进行初始化判断 /// /// //public static IEnumerator DownLoadDataAsync(DownInfo info, int count = 0) //{ // float watieTime = 0; // while (Application.internetReachability == NetworkReachability.NotReachable) // { // UnityLog.Instance.LogError("No Internet Connect"); // yield return new WaitForSeconds(watieTime); // watieTime += 0.1f; // if (watieTime > 1) // { // watieTime = 1; // } // } // DownInfoHandler handler = new DownInfoHandler(info); // Dictionary form = new Dictionary(); // form.Add("appId", info.id.ToString()); // form.Add("searchId", info.searchId.ToString()); // form.Add("recommendId", info.recommendId.ToString()); // form.Add("word", info.word == null ? "" : info.word); // using (UnityWebRequest web = UnityWebRequest.Post(info.server, form)) // { // handler.SetWebRequest(web, info.lastVersionSize); // web.disposeDownloadHandlerOnDispose = true; // web.downloadHandler = handler; // foreach (var item in UrlMgr.Instance.Header) // { // web.SetRequestHeader(item.Key, item.Value); // } // ///请求指定的长度 // web.SetRequestHeader("Range", info.downloadedFileLen.ToString()); // UnityLog.Instance.Log("bytes=" + info.downloadedFileLen + "-" + info.totalSize, 3); // yield return web.SendWebRequest(); // if (web.isNetworkError || web.isHttpError) // { // if (count < maxTryCount) // { // UnityLog.Instance.LogError(info.fileName + "down error ,try again: " + count + web.error + "bytes=" + info.downloadedFileLen + "-" + info.totalSize); // count++; // web.Dispose(); // handler.ErrorDispose(false); // yield return new WaitForSeconds(0.1f); // yield return DownLoadDataAsync(info, count); // yield break; // } // UnityLog.Instance.LogError(web.error + "bytes=" + info.downloadedFileLen + "-" + info.totalSize); // handler.ErrorDispose(); // } // else // { // } // web.Dispose(); // } //} /// /// 断点续传/下载,边下边存 /// 适用于大文件下载。如果是简单的文本或者图片,尽量不要使用此接口 /// /// 目标地址 /// 本地文件路径 /// 下载进度 /// 返回下载的状态,成功或失败,成功后返回改文件的路径 /// //public static IEnumerator DownLoadDataAsync(string url, string path, Action downLoadProcess, Action complete) //{ // ///获取文件的大小 // FileStream fs = null; // long curLen = 0; // ///文件读写异常,返回错误 // try // { // string dir = Path.GetDirectoryName(path); // if (!Directory.Exists(dir)) // { // Directory.CreateDirectory(dir); // } // fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write); // curLen = fs.Length; // UnityLog.Instance.Log("当前文件大小" + curLen, 2); // } // catch (Exception ex) // { // if (fs != null) // { // fs.Close(); // } // UnityLog.Instance.LogError(path + ex.ToString()); // downLoadProcess.Invoke(curLen, 0); // complete?.Invoke(false, ex.ToString()); // yield break; // } // ///请求获取文件的大小 // ///已下载完成,无需再次下载 // long totalLength = 0; // yield return GetDataSize(url, (size) => // { // totalLength = size; // }); // ///当前文件的大小和云端文件大小一致 // ///理论上不会出现这个问题 // if (curLen == totalLength) // { // fs.Close(); // downLoadProcess.Invoke(totalLength, 1); // complete?.Invoke(true, path); // yield break; // } // ///文件异常,删除文件,重新下载 // ///理论上不会出现这个问题 // else if (curLen > totalLength) // { // UnityLog.Instance.LogError("文件大小异常" + curLen + "__" + totalLength); // fs.Close(); // File.Delete(path); // fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write); // curLen = fs.Length; // } // fs.Seek(curLen, SeekOrigin.Begin); // bool isSuccess = true; // yield return RequestDownData(url, (byte[] data, int len) => // { // if (isSuccess && data.Length > 0) // { // try // { // fs.Write(data, 0, len); // fs.Flush(); // curLen += len; // downLoadProcess?.Invoke(curLen, curLen * 1f / totalLength); // } // catch (Exception ex) // { // UnityLog.Instance.LogError(ex.ToString()); // isSuccess = false; // return; // } // } // else // { // ///理论上不会出现这个问题,除非出现异常情况如内存不足等 // //complete?.Invoke(isSuccess, path); // UnityLog.Instance.LogError("Down Error:" + url); // } // }, totalLength, curLen); // fs.Close(); // downLoadProcess.Invoke(totalLength, 1); // complete?.Invoke(isSuccess, path); //} /// /// Get请求下载数据,断点下载,边下载边返回数据进行存储 /// /// url /// 返回获取的数据 /// 文件的总大小 /// 已下载的数据 /// //public static IEnumerator RequestDownData(string url, Action downData, long allLen, long downedLength = 0) //{ // //float downTime = Time.time; // UnityWebRequest web = UnityWebRequest.Get(url); // web.disposeDownloadHandlerOnDispose = true; // DataDownLoadHandler ddh = new DataDownLoadHandler(); // web.downloadHandler = ddh; // ddh.OnReceiveData += downData; // ///请求指定的长度 // web.SetRequestHeader("Range", "bytes=" + downedLength + "-" + allLen); // yield return web.SendWebRequest(); // web.Dispose(); //} /// /// 从URl下载指定的资源 /// /// 资源的地址,可以是网络路径,也可以是本地文件路径 /// 下载的进度,当前已下载文件大小,以及进度 /// /// 请求的参数,如果为空代表Get请求,不为空代表Post请求 /// public static IEnumerator RequestDownData(string url, Action complete, DownloadHandler hander = null, Action updateProcess = null, WWWForm form = null) { UnityWebRequest web; Debug.Log("RequestDownData" + url); if (form == null) { web = UnityWebRequest.Get(url); } else { web = UnityWebRequest.Post(url, form); } if (hander != null) { web.downloadHandler = hander; } web.SendWebRequest(); while (!web.isDone) { updateProcess?.Invoke(web.downloadedBytes, web.downloadProgress); yield return 0; } if (web.isDone) { updateProcess?.Invoke(web.downloadedBytes, 1); } if (web.isNetworkError || web.isHttpError) { complete?.Invoke(web.error, web); Debug.LogError(web.error+url); } else { complete?.Invoke(null, web); } web.Dispose(); } /// /// 上传数据到服务端,并得到服务器返回的结果 /// 与下面的RequestDownData类似,但是更新上传进度,适用于文件上传 /// /// /// /// /// /// public static IEnumerator RequestUpLoadData(string url, WWWForm form, Action updateProcess, Action complete) { UnityWebRequest web = UnityWebRequest.Post(url, form); web.SendWebRequest(); while (!web.isDone) { updateProcess?.Invoke(web.uploadedBytes, web.uploadProgress); yield return 0; } if (web.isDone) { updateProcess?.Invoke(web.uploadedBytes, 1); } if (web.isNetworkError || web.isHttpError) { complete?.Invoke(web.error, web); } else { complete?.Invoke(null, web); } web.Dispose(); } /// /// 是否是忽略的文件类型 /// /// /// public static bool isIgnoreExtension(string ignoreExtension, string suffix) { string[] igs = ignoreExtension.Split('|', ' ', ','); for (int i = 0; i < igs.Length; i++) { if (igs[i] == suffix) { return true; } } return false; } /// /// 保存文本文件到本地 /// 同步方法 /// public static bool SaveDataToFile(string path, string txt) { try { if (!string.IsNullOrEmpty(txt)) { File.WriteAllText(path, txt); return true; } } catch (Exception ex) { UnityLog.Instance.LogError(path + ex.ToString()); } return false; } /// /// 保存二进制字节文件到本地,同步方法 /// /// /// public static bool SaveDataToFile(string path, byte[] data) { try { string dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } FileStream fs = new FileStream(path, FileMode.Create); fs.Write(data, 0, data.Length); fs.Dispose(); fs.Close(); return true; } catch (Exception ex) { UnityLog.Instance.LogError(path + ex.ToString()); } return false; } /// /// 异步保存文本文件 /// /// /// /// /// public static IEnumerator SaveDataToFile(string path, string txt, Action saveProcess, Action onComplete) { yield return SaveDataToFile(path, Encoding.Default.GetBytes(txt), saveProcess, onComplete); } /// /// 保存二进制字节文件到本地,异步方法 /// /// /// private static IEnumerator SaveDataToFile(string path, byte[] data, Action saveProcess, Action onComplete) { bool isSuccess = false; if (data != null && data.Length > 0) { Task task = null; FileStream fs = null; float allData = data.Length; try { fs = new FileStream(path, FileMode.Create); task = fs.WriteAsync(data, 0, data.Length); isSuccess = true; } catch (Exception ex) { UnityLog.Instance.LogError(path + ex.ToString()); path = ex.ToString(); isSuccess = false; } float tmp = 0; float allTime = data.Length / WriteSpeed; ///预计存储完成的时间 while (task != null && !task.IsCompleted) { if (tmp < allTime) { tmp += Time.deltaTime; } saveProcess?.Invoke(tmp / allTime); yield return 0; } saveProcess(1); fs.Dispose(); fs.Close(); } onComplete?.Invoke(isSuccess, path); } /// /// 广度优先,遍历文件 /// /// /// public static void FindFileBreadth(string path, Action callBack) { try { DirectoryInfo di = new DirectoryInfo(path); FileInfo[] fis = di.GetFiles(); for (int i = 0; i < fis.Length; i++) { callBack?.Invoke(fis[i].FullName); } DirectoryInfo[] dis = di.GetDirectories(); for (int j = 0; j < dis.Length; j++) { FindFileBreadth(dis[j].FullName, callBack); } } catch (Exception ex) { UnityLog.Instance.LogError(ex.ToString()); } } /// /// 深度优先,遍历文件 /// /// public static void FindFileByDepth(string dir, Action callBack) { try { DirectoryInfo d = new DirectoryInfo(dir); FileSystemInfo[] fsinfos = d.GetFileSystemInfos(); foreach (FileSystemInfo fsinfo in fsinfos) { if (fsinfo is DirectoryInfo) { FindFileByDepth(fsinfo.FullName, callBack); } else { callBack?.Invoke(fsinfo.FullName); } } } catch (Exception ex) { UnityLog.Instance.LogError(ex.ToString()); } } /// /// 获取文件MD5值 /// /// 文件绝对路径 /// MD5值 public static string GetMD5HashFromFile(string fileName) { try { FileStream file = new FileStream(fileName, FileMode.Open); System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] retVal = md5.ComputeHash(file); file.Close(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < retVal.Length; i++) { sb.Append(retVal[i].ToString("x2")); } return sb.ToString(); } catch (Exception ex) { throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message); } } /// /// 重命名文件 /// /// /// public static void ReNameFile(string file, string newFile) { if (File.Exists(file)) { try { string dir = Path.GetDirectoryName(newFile); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (File.Exists(newFile)) { File.Delete(newFile); } FileInfo info = new FileInfo(file); info.MoveTo(newFile); } catch (Exception ex) { UnityLog.Instance.LogError(file + " is error" + ex.ToString()); } } } /// /// 删除文件 /// /// /// public static void DelFile(string file) { UnityLog.Instance.Log(file + " is Del", 3); if (File.Exists(file)) { try { File.Delete(file); } catch (Exception ex) { UnityLog.Instance.LogError(file + " is error" + ex.ToString()); } } } /// /// 拷贝文件 /// /// /// /// 是否覆盖 /// public static bool CopyDirectory(string SourcePath, string DestinationPath, bool overwriteexisting) { bool ret = false; try { SourcePath = SourcePath.EndsWith(@"\") ? SourcePath : SourcePath + @"\"; DestinationPath = DestinationPath.EndsWith(@"\") ? DestinationPath : DestinationPath + @"\"; if (Directory.Exists(SourcePath)) { if (Directory.Exists(DestinationPath) == false) Directory.CreateDirectory(DestinationPath); foreach (string fls in Directory.GetFiles(SourcePath)) { FileInfo flinfo = new FileInfo(fls); flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting); } foreach (string drs in Directory.GetDirectories(SourcePath)) { DirectoryInfo drinfo = new DirectoryInfo(drs); if (CopyDirectory(drs, DestinationPath + drinfo.Name, overwriteexisting) == false) ret = false; } } ret = true; } catch (Exception ex) { ret = false; UnityLog.Instance.LogError(ex.ToString()); } return ret; } /// /// 文件是否是图片 /// /// /// public static bool IsMoviesFile(string fileName) { if (!string.IsNullOrEmpty(fileName)) { string exten = Path.GetExtension(fileName); return IsMediaType(exten.ToUpper(), MoviesType); } return false; } public static bool IsTextureFile(string fileName) { if (!string.IsNullOrEmpty(fileName)) { string exten = Path.GetExtension(fileName); return IsMediaType(exten.ToUpper(), TexturesType); } return false; } /// /// 判断是否是音频文件 /// MP3,WAV等 /// /// /// public static bool IsAudioFile(string fileName) { if (!string.IsNullOrEmpty(fileName)) { string exten = Path.GetExtension(fileName); return IsMediaType(exten.ToUpper(), AudiosType); } return false; } /// /// 是否是多媒体文件:图片,视频,音频 /// /// /// /// public static bool IsMediaType(string fileName, string[] types) { if (!string.IsNullOrEmpty(fileName) && types != null) { for (int i = 0; i < types.Length; i++) { if (TexturesType[i] == fileName) { return true; } } } return false; } /// /// 是否多媒体文件 /// 音频,视频,图片 /// /// /// public static bool IsMediaType(string fileName) { if (!string.IsNullOrEmpty(fileName)) { string exten = Path.GetExtension(fileName); exten = exten.ToUpper(); return IsMediaType(exten, TexturesType) || IsMediaType(exten, MoviesType) || IsMediaType(exten, AudiosType); } return false; } /// /// 是否存在某文件 /// /// /// public static bool Exists(string file) { return File.Exists(file); } } }