using System; using System.IO; using System.Security.Cryptography; using System.Text; using Neatly.Module; using Neatly.Native; using UnityEngine; public class FileModule : ModuleSingleton { private static MD5CryptoServiceProvider s_md5Provider = new MD5CryptoServiceProvider(); public enum enFileOperation { ReadFile, WriteFile, DeleteFile, CreateDirectory, DeleteDirectory } public override void Init() { CreateDirectory(NeatlyConfig.PATH_UPDATE_BUNDLE); CreateDirectory(NeatlyConfig.PATH_UPDATE_LUA); NDebug.Log(NeatlyConfig.PATH_UPDATE_BUNDLE); NDebug.Log(NeatlyConfig.PATH_UPDATE_LUA); } #region 文件操作 public bool IsFileExist(string filePath) { return File.Exists(filePath); } public bool IsDirectoryExist(string directory) { return Directory.Exists(directory); } public bool CreateDirectory(string directory) { if (IsDirectoryExist(directory)) { return true; } bool success = tryAction(() => { Directory.CreateDirectory(directory); }, exception => { Debug.LogFormat("Create Directory {0} Error! Exception = {1}", directory, exception); }); return success; } public bool DeleteFile(string filePath) { if (!IsFileExist(filePath)) { return true; } bool success = tryAction(() => { File.Delete(filePath); }, exception => { Debug.LogFormat("Delete File {0} Error! Exception = {1}", filePath, exception); }); return success; } public bool DeleteDirectory(string directory) { if (!IsDirectoryExist(directory)) { return true; } bool success = tryAction(() => { Directory.Delete(directory, true); }, exception => { Debug.LogFormat("Delete Directory {0} Error! Exception = {1}", directory, exception); }); return success; } public void ClearDirectory(string directory) { DeleteDirectory(directory); CreateDirectory(directory); } public long GetFileLength(string filePath) { long fileLength = 0; if (!IsFileExist(filePath)) { return fileLength; } tryAction(() => { FileInfo fileInfo = new FileInfo(filePath); fileLength = fileInfo.Length; }, exception => { Debug.LogFormat("Get FileLength of {0} Error! Exception = {1}", filePath, exception); }); return fileLength; } public byte[] ReadFile(string filePath) { if (!IsFileExist(filePath)) { return null; } byte[] array = null; tryAction(() => { array = File.ReadAllBytes(filePath); }, exception => { Debug.LogFormat("Read File {0} Error! Exception = {1}", filePath, exception); }); return array; } public bool WriteFile(string filePath, byte[] data) { bool success = tryAction(() => { File.WriteAllBytes(filePath, data); }, exception => { Debug.LogFormat("Write File {0} Error! Exception = {1}", filePath, exception); DeleteFile(filePath); }); return success; } public bool WriteFile(string filePath, byte[] data, int offset, int length) { FileStream fileStream = null; bool success = tryAction(() => { fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite); fileStream.Write(data, offset, length); fileStream.Close(); }, exception => { Debug.LogFormat("Write File {0} Error! Exception = {1}", filePath, exception); DeleteFile(filePath); }, () => { fileStream?.Close(); }); return success; } public byte[] ReadFileBytes(string root, string fileName) { string path = null; byte[] byteArray = null; #if !UNITY_EDITOR path = $"{NeatlyConfig.PATH_UPDATE}/{root}/{fileName}"; byteArray = ReadFile(path); if (byteArray != null) { return byteArray; } #if UNITY_ANDROID path = $"{root}/{fileName}"; byteArray = AndroidHelper.ReadBytes(path); #else path = $"{Application.streamingAssetsPath}/{root}/{fileName}"; byteArray = ReadFile(path); #endif if (byteArray != null) { return byteArray; } #endif return ReadEditorFile(root, fileName); } public byte[] ReadEditorFile(string root, string fileName) { var path = $"assets/{root}/{fileName}"; return ReadFile(path); } public byte[] ReadUpdateLua(string fileName) { string path = string.Format("{0}/{1}", NeatlyConfig.PATH_UPDATE_LUA, fileName); return ReadFile(path); } public byte[] ReadBytes(string path) { #if !UNITY_EDITOR && UNITY_ANDROID // 如果是读apk包里的资源,使用Android帮助库加载 if (path.Contains(NeatlyConfig.PATH_PACKAGE_BUNDLE) || path.Contains(NeatlyConfig.PATH_PACKAGE_LUA)) { string fileName = path.Replace(NeatlyConfig.PATH_PACKAGE + "/", ""); return AndroidHelper.ReadBytes(fileName); } #endif if (!IsFileExist(path)) { Debug.Log("error:" + path); } return File.ReadAllBytes(path); } public byte[] ReadEditorLua(string fileName) { var path = string.Format("assets/lua/{0}.lua", fileName); if (!IsFileExist(path)) { path = string.Format("assets/tolua/lua/{0}.lua", fileName); } return ReadFile(path); } public void CopyFile(string path, string outPath) { #if !UNITY_EDITOR && UNITY_ANDROID string fileName = path.Replace(NeatlyConfig.PATH_PACKAGE + "/", ""); AndroidHelper.CopyFile(fileName, outPath); return; #endif File.Copy(path, outPath, true); } #endregion #region 压缩 public void Uncompress(string path, string outPath) { string deleteFilePath = null; string copyPath = path; if (path.Contains(NeatlyConfig.PATH_PACKAGE_BUNDLE) || path.Contains(NeatlyConfig.PATH_PACKAGE_LUA)) { string fileName = path.Replace(NeatlyConfig.PATH_PACKAGE + "/", ""); copyPath = Path.Combine(NeatlyConfig.PATH_ANDROID_PACKAGE_TEMP, fileName); deleteFilePath = copyPath; CreateDirectory(NeatlyConfig.PATH_ANDROID_PACKAGE_TEMP_BUNDLE); CreateDirectory(Path.Combine(NeatlyConfig.PATH_ANDROID_PACKAGE_TEMP, NeatlyConfig.PATH_ANDROID_PACKAGE_TEMP_LUA)); #if !UNITY_EDITOR && UNITY_ANDROID AndroidHelper.CopyFile(fileName, copyPath); #else File.Copy(path, copyPath, true); #endif } LzmaHelper.Decompress(copyPath, outPath); if (!string.IsNullOrEmpty(deleteFilePath)) { DeleteFile(deleteFilePath); } } #endregion #region MD5 public string GetFileMd5(string filePath) { if (!IsFileExist(filePath)) { return string.Empty; } return BitConverter.ToString(s_md5Provider.ComputeHash(ReadFile(filePath))).Replace("-", string.Empty); } public static string GetMd5(byte[] data) { return BitConverter.ToString(s_md5Provider.ComputeHash(data)).Replace("-", string.Empty); } public static string GetMd5(string str) { return BitConverter.ToString(s_md5Provider.ComputeHash(Encoding.UTF8.GetBytes(str))).Replace("-", string.Empty); } #endregion #region Util public static string CombinePath(string path1, string path2) { return string.Format("{0}/{1}", path1, path2); } public static string CombinePaths(params string[] values) { if (values.Length <= 0) { return string.Empty; } if (values.Length == 1) { return CombinePath(values[0], string.Empty); } if (values.Length > 1) { string text = CombinePath(values[0], values[1]); for (int i = 2; i < values.Length; i++) { text = CombinePath(text, values[i]); } return text; } return string.Empty; } private static bool tryAction(Action doAction, Action exceptionExitAction, Action failAction = null) { int count = 3; bool success = false; for (int i = 0; i < count; i++) { try { doAction(); success = true; break; } catch (Exception ex) { failAction?.Invoke(); exceptionExitAction(ex); } } return success; } #endregion }