using System; using System.IO; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace Luban.Common.Utils { public static class FileUtil { private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger(); public static string GetApplicationDirectory() { return Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().Location); } public static string GetPathRelateApplicationDirectory(string relatePath) { return Path.Combine(GetApplicationDirectory(), relatePath); } public static string GetFileName(string path) { int index = path.Replace('\\', '/').LastIndexOf('/'); return index >= 0 ? path[(index + 1)..] : path; } public static string GetParent(string path) { int index = path.Replace('\\', '/').LastIndexOf('/'); return index >= 0 ? path[..index] : "."; } public static string GetFileNameWithoutExt(string file) { int index = file.LastIndexOf('.'); return index >= 0 ? file.Substring(0, index) : file; } public static string GetFileExtension(string file) { int index = file.LastIndexOf('.'); return index >= 0 ? file.Substring(index + 1) : ""; } public static string GetPathRelateRootFile(string rootFile, string file) { return Combine(GetParent(rootFile), file); } /// /// 忽略以 文件名以 '.' '_' '~' 开头的文件 /// /// /// public static bool IsValidInputFile(string file) { if (!File.Exists(file)) { return false; } var f = new FileInfo(file); string fname = f.Name; return !fname.StartsWith('.') && !fname.StartsWith('_') && !fname.StartsWith('~'); } public static string CalcMD5(byte[] srcBytes) { using MD5 md5 = MD5.Create(); var md5Bytes = md5.ComputeHash(srcBytes); var s = new StringBuilder(md5Bytes.Length * 2); foreach (var b in md5Bytes) { s.Append(b.ToString("X")); } return s.ToString(); } public static string Standardize(string path) { return path.Replace('\\', '/'); } public static string Combine(string parent, string sub) { return Standardize(Path.Combine(parent, sub)); } public static bool IsExcelFile(string fullName) { return fullName.EndsWith(".csv", StringComparison.Ordinal) || fullName.EndsWith(".xls", StringComparison.Ordinal) || fullName.EndsWith(".xlsx", StringComparison.Ordinal); } public static (string, string) SplitFileAndSheetName(string url) { int sheetSepIndex = url.IndexOf('@'); if (sheetSepIndex < 0) { return (url, null); } else { int lastPathSep = url.LastIndexOf('/', sheetSepIndex); if (lastPathSep >= 0) { return (url[0..(lastPathSep + 1)] + url[(sheetSepIndex + 1)..], url[(lastPathSep + 1)..sheetSepIndex]); } else { return (url[(sheetSepIndex + 1)..], url[(lastPathSep + 1)..sheetSepIndex]); } } } public static async Task SaveFileAsync(string relateDir, string filePath, byte[] content) { // 调用此接口时,已保证 文件必然是改变的,不用再检查对比文件 var outputPath = Standardize(relateDir != null ? System.IO.Path.Combine(relateDir, filePath) : filePath); Directory.GetParent(outputPath).Create(); if (File.Exists(outputPath)) { s_logger.Info("[override] {file}", outputPath); if (File.GetAttributes(outputPath).HasFlag(FileAttributes.ReadOnly)) { File.SetAttributes(outputPath, FileAttributes.Normal); } } else { s_logger.Info("[new] {file}", outputPath); } await WriteAllBytesAsync(outputPath, content); } public static async Task ReadAllBytesAsync(string file) { // File.ReadAllBytesAsync 无法读取被打开的excel文件,只好重新实现了一个 using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); long count = fs.Length; var bytes = new byte[count]; int writeIndex = 0; while (writeIndex < count) { int n = await fs.ReadAsync(bytes, writeIndex, (int)count - writeIndex, default); writeIndex += n; } return bytes; } public static byte[] ReadAllBytes(string file) { // File.ReadAllBytesAsync 无法读取被打开的excel文件,只好重新实现了一个 using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); long count = fs.Length; var bytes = new byte[count]; int writeIndex = 0; while (writeIndex < count) { int n = fs.Read(bytes, writeIndex, (int)count - writeIndex); writeIndex += n; } return bytes; } public static async Task WriteAllBytesAsync(string file, byte[] bytes) { using var fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite); long count = bytes.LongLength; fs.SetLength(count); fs.Seek(0, SeekOrigin.Begin); await fs.WriteAsync(bytes); } public static void DeleteDirectoryRecursive(string rootDir) { string[] files = Directory.GetFiles(rootDir); string[] dirs = Directory.GetDirectories(rootDir); foreach (string file in files) { File.SetAttributes(file, FileAttributes.Normal); File.Delete(file); } foreach (string dir in dirs) { DeleteDirectoryRecursive(dir); } Directory.Delete(rootDir, false); } } }