| | |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_Core; |
| | | using WIDESEAWCS_Core.BaseServices; |
| | | using WIDESEAWCS_ISystemRepository; |
| | | using WIDESEAWCS_ISystemServices; |
| | |
| | | { |
| | | public class Sys_LogService : ServiceBase<Sys_Log, ISys_LogRepository>, ISys_LogService |
| | | { |
| | | private readonly string[] LogFolders = new[] { "Log", "Log_PLCReadWrite" }; |
| | | private int fileId = 2020; |
| | | public Sys_LogService(ISys_LogRepository BaseDal) : base(BaseDal) |
| | | { |
| | | } |
| | | |
| | | public WebResponseContent GetLogName() |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | var data = new List<object>(); |
| | | fileId = 2020; // 重置ID |
| | | |
| | | foreach (string folderName in LogFolders) |
| | | { |
| | | var folderPath = Path.Combine(AppContext.BaseDirectory, folderName); |
| | | var folderInfo = new DirectoryInfo(folderPath); |
| | | |
| | | if (!folderInfo.Exists) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | var folderData = BuildFolderTree(folderInfo, folderName); |
| | | data.Add(folderData); |
| | | } |
| | | |
| | | return data.Any() |
| | | ? WebResponseContent.Instance.OK(data: data) |
| | | : WebResponseContent.Instance.Error("未找到日志文件夹"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | } |
| | | |
| | | |
| | | public WebResponseContent GetLog(string fileName) |
| | | { |
| | | try |
| | | { |
| | | if (string.IsNullOrEmpty(fileName)) |
| | | { |
| | | return WebResponseContent.Instance.Error("文件名不能为空"); |
| | | } |
| | | |
| | | FileSearchResult searchResult = null; |
| | | |
| | | foreach (string folderName in LogFolders) |
| | | { |
| | | var folderPath = Path.Combine(AppContext.BaseDirectory, folderName); |
| | | var folderInfo = new DirectoryInfo(folderPath); |
| | | |
| | | if (!folderInfo.Exists) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | searchResult = FindFileWithInfo(folderInfo, fileName, folderName); |
| | | if (searchResult != null) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (searchResult == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"未找到日志文件: {fileName}"); |
| | | } |
| | | |
| | | // 读取文件内容 |
| | | var fileContent = ReadLogFileContent(searchResult.File.FullName); |
| | | |
| | | // 返回包含元数据的结果 |
| | | var result = new |
| | | { |
| | | fileName = searchResult.File.Name, |
| | | fullPath = searchResult.File.FullName, |
| | | fatherNode = searchResult.SourceFolder, |
| | | fileSize = GetFileSize(searchResult.File.Length), |
| | | lastWriteTime = searchResult.File.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"), |
| | | content = fileContent, |
| | | lineCount = fileContent.Count |
| | | }; |
| | | |
| | | return WebResponseContent.Instance.OK(data: result); |
| | | } |
| | | catch (IOException ex) |
| | | { |
| | | if (IsFileLockedException(ex)) |
| | | { |
| | | return WebResponseContent.Instance.Error($"日志文件正在被系统写入,请稍后再试"); |
| | | } |
| | | return WebResponseContent.Instance.Error($"打开日志文件错误,{ex.Message}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"打开日志文件错误,{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #region MyRegion |
| | | private object BuildFolderTree(DirectoryInfo folder, string displayName) |
| | | { |
| | | var children = new List<object>(); |
| | | |
| | | // 处理子目录 |
| | | foreach (var subDir in folder.GetDirectories().Where(x => x.Name != "Info").OrderByDescending(x => x.CreationTime)) |
| | | { |
| | | var files = subDir.GetFiles() |
| | | .Select(file => new |
| | | { |
| | | label = file.Name, |
| | | id = fileId++, |
| | | hidden = true, |
| | | fatherNode = subDir.Name, |
| | | fullPath = file.FullName, |
| | | lastWriteTime = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss") |
| | | }) |
| | | .ToList(); |
| | | |
| | | if (files.Any()) |
| | | { |
| | | children.Add(new |
| | | { |
| | | label = subDir.Name, |
| | | children = files, |
| | | id = subDir.Name.GetHashCode(), |
| | | hidden = false |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // 处理根目录文件 |
| | | var rootFiles = folder.GetFiles() |
| | | .Select(file => new |
| | | { |
| | | label = file.Name, |
| | | id = fileId++, |
| | | hidden = true, |
| | | fatherNode = folder.Name, |
| | | fullPath = file.FullName, |
| | | lastWriteTime = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss") |
| | | }) |
| | | .ToList(); |
| | | |
| | | if (rootFiles.Any()) |
| | | { |
| | | children.Add(new |
| | | { |
| | | label = folder.Name, |
| | | children = rootFiles, |
| | | id = folder.Name.GetHashCode(), |
| | | hidden = false |
| | | }); |
| | | } |
| | | |
| | | return new |
| | | { |
| | | label = displayName, |
| | | children = children, |
| | | id = displayName.GetHashCode(), |
| | | hidden = false, |
| | | fatherNode = folder.Name, |
| | | isRoot = true |
| | | }; |
| | | } |
| | | |
| | | private List<string> ReadLogFileContent(string filePath) |
| | | { |
| | | var lines = new List<string>(); |
| | | |
| | | using (FileStream stream = new FileStream( |
| | | filePath, |
| | | FileMode.Open, |
| | | FileAccess.Read, |
| | | FileShare.ReadWrite)) |
| | | using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) |
| | | { |
| | | // 如果文件太大,只读取最后1000行(可选) |
| | | var fileInfo = new FileInfo(filePath); |
| | | if (fileInfo.Length > 5 * 1024 * 1024) // 大于5MB |
| | | { |
| | | return ReadLastLines(reader, 1000); |
| | | } |
| | | |
| | | // 读取全部内容 |
| | | while (!reader.EndOfStream) |
| | | { |
| | | var line = reader.ReadLine(); |
| | | lines.Add(line); |
| | | } |
| | | } |
| | | |
| | | return lines; |
| | | } |
| | | |
| | | private List<string> ReadLastLines(StreamReader reader, int lineCount) |
| | | { |
| | | var lines = new Queue<string>(); |
| | | string line; |
| | | |
| | | while ((line = reader.ReadLine()) != null) |
| | | { |
| | | lines.Enqueue(line); |
| | | if (lines.Count > lineCount) |
| | | { |
| | | lines.Dequeue(); |
| | | } |
| | | } |
| | | |
| | | return lines.ToList(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 文件查找结果 |
| | | /// </summary> |
| | | private class FileSearchResult |
| | | { |
| | | public FileInfo File { get; set; } |
| | | public string SourceFolder { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查找文件并返回详细信息 |
| | | /// </summary> |
| | | private FileSearchResult FindFileWithInfo(DirectoryInfo folder, string fileName, string sourceFolder) |
| | | { |
| | | // 查找当前目录 |
| | | var file = folder.GetFiles().FirstOrDefault(x => x.Name == fileName); |
| | | if (file != null) |
| | | { |
| | | return new FileSearchResult |
| | | { |
| | | File = file, |
| | | SourceFolder = sourceFolder |
| | | }; |
| | | } |
| | | |
| | | // 递归查找子目录 |
| | | foreach (var subDir in folder.GetDirectories().Where(x => x.Name != "Info")) |
| | | { |
| | | var result = FindFileWithInfo(subDir, fileName, sourceFolder); |
| | | if (result != null) |
| | | { |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取可读的文件大小 |
| | | /// </summary> |
| | | private string GetFileSize(long bytes) |
| | | { |
| | | string[] sizes = { "B", "KB", "MB", "GB" }; |
| | | double len = bytes; |
| | | int order = 0; |
| | | while (len >= 1024 && order < sizes.Length - 1) |
| | | { |
| | | order++; |
| | | len = len / 1024; |
| | | } |
| | | return $"{len:0.##} {sizes[order]}"; |
| | | } |
| | | |
| | | private bool IsFileLockedException(IOException ex) |
| | | { |
| | | int errorCode = ex.HResult & 0xFFFF; |
| | | return errorCode == 32 || errorCode == 33; // ERROR_SHARING_VIOLATION or ERROR_LOCK_VIOLATION |
| | | } |
| | | #endregion |
| | | } |
| | | } |