You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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报告,包含表头样式和自动列宽。

使用注意事项

  1. 若需商用,请更换EPPlus的许可证类型。
  2. 可根据实际日志格式调整正则表达式和错误名称提取逻辑。
  3. 处理大文件时,File.ReadLines会逐行读取,避免内存溢出。

内容的提问来源于stack exchange,提问作者Mehmet Ali Karabulut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:02:34