// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! namespace Admin.NET.Core; /// /// 文件帮助类 /// public static class FileHelper { #region 文件操作 /// /// 读取文件内容到字符串 /// /// 要读取的文件路径 /// 文件内容为字符串 public static string ReadAllText(string filePath) { return File.ReadAllText(filePath); } /// /// 打开一个文本文件,读取文件的所有行,然后关闭文件 /// /// 要打开以进行读取的文件路径 /// 包含文件所有行的字符串 public static async Task ReadAllTextAsync(string filePath) { using var reader = File.OpenText(filePath); return await reader.ReadToEndAsync(); } /// /// 打开一个文本文件,读取文件的所有字节,然后关闭文件 /// /// 要打开以进行读取的文件路径 /// 包含文件所有字节的字节数组 public static async Task ReadAllBytesAsync(string filePath) { await using var stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); var result = new byte[stream.Length]; _ = await stream.ReadAsync(result.AsMemory(0, (int)stream.Length)); return result; } /// /// 打开一个文本文件,读取文件的所有行,然后关闭文件 /// /// 要打开以进行读取的文件 /// 文件的编码默认为 UTF8 /// 指定操作系统应如何打开文件默认为 Open /// 定义对文件的读取、写入或读写访问的常量默认为 Read /// 包含控制其他 FileStream 对象可以对同一文件拥有的访问类型的常量默认为 Read /// StreamReader 缓冲区的长度默认为 4096 /// 指示 FileStream 选项默认为 Asynchronous(文件将用于异步读取)和 SequentialScan(文件将从开始到末尾顺序访问) /// 包含文件所有行的字符串数组 public static async Task ReadAllLinesAsync(string path, Encoding? encoding = null, FileMode fileMode = FileMode.Open, FileAccess fileAccess = FileAccess.Read, FileShare fileShare = FileShare.Read, int bufferSize = 4096, FileOptions fileOptions = FileOptions.Asynchronous | FileOptions.SequentialScan) { encoding ??= Encoding.UTF8; List lines = []; await using (FileStream stream = new(path, fileMode, fileAccess, fileShare, bufferSize, fileOptions)) { using StreamReader reader = new(stream, encoding); while (await reader.ReadLineAsync() is { } line) { lines.Add(line); } } return [.. lines]; } /// /// 打开一个文本文件,读取不包含 BOM 的内容 /// /// 要打开以进行读取的文件 /// 包含文件所有行的字符串 public static async Task ReadWithoutBomAsync(string path) { var content = await ReadAllBytesAsync(path); return ConvertFromBytesWithoutBom(content)!; } /// /// 将字节数组 byte[]转换为不包含字节顺序标记(BOM)的字符串 /// /// 要转换为字符串的 byte[]数组 /// 获取字符串的编码默认为 UTF8 /// 转换得到的字符串 private static string? ConvertFromBytesWithoutBom(byte[]? bytes, Encoding? encoding = null) { if (bytes is null) { return null; } encoding ??= Encoding.UTF8; var hasBom = bytes is [0xEF, 0xBB, 0xBF, ..]; return hasBom ? encoding.GetString(bytes, 3, bytes.Length - 3) : encoding.GetString(bytes); } /// /// 将文本内容写入到文件 /// /// 要写入的文件路径 /// 要写入的文本内容 public static void WriteAllText(string filePath, string content) { File.WriteAllText(filePath, content); } /// /// 将文本内容追加到文件 /// /// 要追加的文件路径 /// 要追加的文本内容 public static void AppendAllText(string filePath, string content) { File.AppendAllText(filePath, content); } /// /// 创建文件,如果文件不存在 /// /// 文件路径 public static void CreateIfNotExists(string filePath) { if (!File.Exists(filePath)) { _ = File.Create(filePath); } } /// /// 删除一个文件,如果文件存在 /// /// 要删除的文件路径 public static void DeleteIfExists(string filePath) { if (File.Exists(filePath)) { File.Delete(filePath); } } /// /// 移动文件到另一个位置 /// /// 当前文件的路径 /// 目标文件的路径 public static void Move(string sourcePath, string destinationPath) { File.Move(sourcePath, destinationPath); } /// /// 复制文件到另一个位置 /// /// 当前文件的路径 /// 目标文件的路径 /// 如果目标位置已经存在同名文件,是否覆盖 public static void Copy(string sourcePath, string destinationPath, bool overwrite = false) { File.Copy(sourcePath, destinationPath, overwrite); } /// /// 清空文件内容 /// /// 文件的绝对路径 public static void Clean(string filePath) { if (!File.Exists(filePath)) { return; } // 删除文件 File.Delete(filePath); // 重新创建该文件 _ = File.Create(filePath); } #endregion 文件操作 #region 文件信息 /// /// 获取文件的哈希值 /// /// 要计算哈希值的文件路径 /// 文件的哈希值 public static string GetHash(string filePath) { using var stream = File.OpenRead(filePath); return HashHelper.StreamMd5(stream); } /// /// 获取指定文件大小 /// /// /// public static long GetSize(string filePath) { return new FileInfo(filePath).Length; } /// /// 从文件的绝对路径中获取文件名(包含扩展方法名) /// /// /// public static string GetName(string filePath) { return Path.GetFileName(filePath); } /// /// 获取随机文件名 /// /// public static string GetRandomName() { return Path.GetRandomFileName(); } /// /// 根据时间得到文件名 /// yyyyMMddHHmmssfff /// /// public static string GetDateName() { return DateTime.Now.ToString("yyyyMMddHHmmssfff"); } /// /// 从文件的绝对路径中获取扩展方法名 /// 文件扩展方法名是包含点(.)的 /// /// /// public static string GetExtension(string filePath) { return Path.GetExtension(filePath); } /// /// 从文件的绝对路径中获取文件名(不包含扩展方法名) /// /// /// public static string GetNameWithoutExtension(string filePath) { return Path.GetFileNameWithoutExtension(filePath); } /// /// 生成唯一的文件名,上传文件使用 /// /// 包含扩展方法名的源文件名 /// public static string GetUniqueName(string fileName) { var fileNameWithoutExtension = GetNameWithoutExtension(fileName); var fileExtension = GetExtension(fileName); var uniqueFileName = $"{fileNameWithoutExtension}_{GetDateName()}_{GetRandomName()}"; return uniqueFileName + fileExtension; } /// /// 获取文本文件的行数 /// /// 文件的绝对路径 /// public static int GetTextLineCount(string filePath) { // 将文本文件的各行读到一个字符串数组中 var rows = File.ReadAllLines(filePath); // 返回行数 return rows.Length; } #endregion 文件信息 #region 文件检查 /// /// 检查文件是否存在 /// /// 要检查的文件路径 /// 如果文件存在返回 true,否则返回 false public static bool Exists(string filePath) { return File.Exists(filePath); } /// /// 检查文件是否被锁定 /// /// 要检查的文件路径 /// true 如果文件没有被锁定,可以进行读写操作,否则 false public static bool IsUnlocked(string filePath) { try { using var fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // 如果没有异常,文件没有被锁定 return true; } catch (IOException) { // 如果发生异常,文件可能被锁定 return false; } } #endregion 文件检查 }