如何用C#将多份TXT错误日志拆分并导出至Excel生成报告
解决方案:C# 错误日志提取与Excel报告生成
原代码问题分析
- 循环索引错误:使用
line.Length遍历拆分后的数组,会导致索引越界异常,正确应使用pieces.Length。 - 拆分逻辑缺陷:直接用
Split('|')处理连续竖线会生成大量空字符串,无法精准提取字段。 - 缺少无效行过滤:未处理格式异常的日志行(如示例中无竖线的乱码行)。
- 无统计与Excel生成逻辑:仅做了简单拆分,未实现错误聚合统计和报告导出。
完整实现方案
1. 准备工作
安装NuGet包EPPlus(用于Excel生成):
Install-Package EPPlus
2. 代码实现
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using OfficeOpenXml; using System.Windows.Forms; namespace ErrorLogAnalyzer { // 单条错误日志的数据模型 public class ErrorLogEntry { public DateTime LogDate { get; set; } public string ErrorCode { get; set; } // 对应|后的数字,如1、2、111 public string ErrorType { get; set; } // 如ERROR public string ErrorName { get; set; } // 提取Ex:、ExCode:等作为错误名称 public string ErrorContent { get; set; } // 完整错误描述 public string SourceFile { get; set; } // 来源日志文件名 } // 错误统计结果模型 public class ErrorStatistic { public string ErrorName { get; set; } public string ErrorCode { get; set; } public DateTime FirstOccurrence { get; set; } public DateTime LastOccurrence { get; set; } public int RepeatCount { get; set; } public string ErrorContent { get; set; } public string SourceFiles { get; set; } // 涉及的日志文件 } class Program { // 匹配有效日志行的正则表达式:匹配日期、错误代码、错误类型、后续内容 private static readonly Regex LogRegex = new Regex( @"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}) \|(\d+)\|(ERROR)\|(.*)$", RegexOptions.Compiled); static void Main(string[] args) { // 让用户选择多个日志文件 var openFileDialog = new OpenFileDialog(); openFileDialog.Multiselect = true; openFileDialog.Filter = "文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*"; if (openFileDialog.ShowDialog() != DialogResult.OK) return; var allLogEntries = new List<ErrorLogEntry>(); // 批量解析选中的文件 foreach (var filePath in openFileDialog.FileNames) { var fileName = Path.GetFileName(filePath); ParseLogFile(filePath, fileName, allLogEntries); Console.WriteLine($"已解析文件:{fileName}"); } // 统计错误信息 var errorStats = AggregateErrorStats(allLogEntries); // 生成Excel报告 GenerateExcelReport(errorStats, "错误日志统计报告.xlsx"); Console.WriteLine("Excel报告已生成,按任意键退出..."); Console.ReadKey(); } /// <summary> /// 解析单个日志文件 /// </summary> private static void ParseLogFile(string filePath, string fileName, List<ErrorLogEntry> entries) { try { foreach (var line in File.ReadLines(filePath)) { var match = LogRegex.Match(line.Trim()); if (!match.Success) continue; // 跳过无效行 // 提取匹配到的分组 var logDateStr = match.Groups[1].Value; var errorCode = match.Groups[2].Value; var errorType = match.Groups[3].Value; var contentPart = match.Groups[4].Value.Trim(); // 提取错误名称和内容(处理空字符串情况) string errorName = "未知错误"; string errorContent = contentPart; if (!string.IsNullOrEmpty(contentPart)) { if (contentPart.StartsWith("Ex:")) { errorName = "通用异常"; errorContent = contentPart.Substring(3).Trim(); } else if (contentPart.StartsWith("ExCode:")) { errorName = "编码异常"; errorContent = contentPart.Substring(7).Trim(); } } // 转换日期 if (DateTime.TryParseExact(logDateStr, "yyyy-MM-dd HH:mm:ss,fff", null, System.Globalization.DateTimeStyles.None, out DateTime logDate)) { entries.Add(new ErrorLogEntry { LogDate = logDate, ErrorCode = errorCode, ErrorType = errorType, ErrorName = errorName, ErrorContent = errorContent, SourceFile = fileName }); } } } catch (Exception ex) { Console.WriteLine($"解析文件{fileName}出错:{ex.Message}"); } } /// <summary> /// 按错误特征聚合统计 /// </summary> private static List<ErrorStatistic> AggregateErrorStats(List<ErrorLogEntry> entries) { // 按错误代码+错误内容分组,确保相同错误被合并 var grouped = entries.GroupBy(e => $"{e.ErrorCode}_{e.ErrorContent}") .Select(g => new ErrorStatistic { ErrorCode = g.First().ErrorCode, ErrorName = g.First().ErrorName, FirstOccurrence = g.Min(e => e.LogDate), LastOccurrence = g.Max(e => e.LogDate), RepeatCount = g.Count(), ErrorContent = g.First().ErrorContent, SourceFiles = string.Join(";", g.Select(e => e.SourceFile).Distinct()) }) .OrderByDescending(s => s.RepeatCount) .ToList(); return grouped; } /// <summary> /// 生成Excel报告 /// </summary> private static void GenerateExcelReport(List<ErrorStatistic> stats, string outputPath) { // 设置EPPlus许可证(非商用免费) ExcelPackage.LicenseContext = LicenseContext.NonCommercial; using (var package = new ExcelPackage()) { var worksheet = package.Workbook.Worksheets.Add("错误统计"); // 写入表头 worksheet.Cells[1, 1].Value = "错误名称"; worksheet.Cells[1, 2].Value = "错误代码"; worksheet.Cells[1, 3].Value = "首次出现日期"; worksheet.Cells[1, 4].Value = "末次出现日期"; worksheet.Cells[1, 5].Value = "重复次数"; worksheet.Cells[1, 6].Value = "错误内容"; worksheet.Cells[1, 7].Value = "来源文件"; // 设置表头样式 var headerRange = worksheet.Cells[1, 1, 1, 7]; headerRange.Style.Font.Bold = true; headerRange.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; headerRange.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray); // 写入统计数据 int row = 2; foreach (var stat in stats) { worksheet.Cells[row, 1].Value = stat.ErrorName; worksheet.Cells[row, 2].Value = stat.ErrorCode; worksheet.Cells[row, 3].Value = stat.FirstOccurrence.ToString("yyyy-MM-dd HH:mm:ss"); worksheet.Cells[row, 4].Value = stat.LastOccurrence.ToString("yyyy-MM-dd HH:mm:ss"); worksheet.Cells[row, 5].Value = stat.RepeatCount; worksheet.Cells[row, 6].Value = stat.ErrorContent; worksheet.Cells[row, 7].Value = stat.SourceFiles; row++; } // 自动调整列宽 worksheet.Cells.AutoFitColumns(); // 保存文件 package.SaveAs(new FileInfo(outputPath)); } } } }
代码说明
- 正则解析:用正则精准匹配有效日志行,避免Split处理连续竖线的问题,同时过滤无效行。
- 数据模型:用
ErrorLogEntry存储单条日志信息,ErrorStatistic存储聚合后的统计结果。 - 多文件支持:通过
OpenFileDialog让用户选择多个文件,批量解析。 - 错误聚合:按错误代码+错误内容分组,统计重复次数、日期范围和涉及文件。
- Excel生成:使用EPPlus库创建格式化的Excel报告,包含表头样式和自动列宽。
使用注意事项
- 若需商用,请更换EPPlus的许可证类型。
- 可根据实际日志格式调整正则表达式和错误名称提取逻辑。
- 处理大文件时,
File.ReadLines会逐行读取,避免内存溢出。
内容的提问来源于stack exchange,提问作者Mehmet Ali Karabulut
相关产品推荐
相关产品推荐

