C#分段CSV文件解析求助:新手求编写对应解析器
C#分段CSV文件解析实现方案
一、定义数据实体类
先对应每个段落的结构创建C#实体类,让解析后的数据能清晰存储:
// 对应[INFO]段的数据结构 public class Info { public string LineName { get; set; } public string MachineSn { get; set; } public string MachineName { get; set; } public string OperatorId { get; set; } } // 对应[PANEL_INSP_RESULT]段的数据结构 public class PanelInspResult { public string ModelName { get; set; } public string ModelCode { get; set; } public string PanelSide { get; set; } public int Index { get; set; } public string Barcode { get; set; } public string Date { get; set; } public string StartTime { get; set; } public string EndTime { get; set; } public string DefectName { get; set; } public string DefectCode { get; set; } public string Result { get; set; } } // 对应[BOARD_INSP_RESULT]段的数据结构 public class BoardInspResult { public int BoardNo { get; set; } public string Barcode { get; set; } public string DefectName { get; set; } public string DefectCode { get; set; } public string Badmark { get; set; } public string Result { get; set; } } // 对应[COMPONENT_INSP_RESULT]段的数据结构 public class ComponentInspResult { public int BoardNo { get; set; } public string LocationName { get; set; } public string PinNumber { get; set; } public string PosX { get; set; } public string PosY { get; set; } public string DefectName { get; set; } public string DefectCode { get; set; } public string Result { get; set; } } // 统一存储所有解析后的数据 public class ParsedCsvData { public Info Info { get; set; } public List<PanelInspResult> PanelResults { get; set; } = new List<PanelInspResult>(); public List<BoardInspResult> BoardResults { get; set; } = new List<BoardInspResult>(); public List<ComponentInspResult> ComponentResults { get; set; } = new List<ComponentInspResult>(); }
二、核心解析逻辑
实现分段读取、表头匹配、数据映射的核心代码:
public class SegmentedCsvParser { public static ParsedCsvData ParseFile(string filePath) { var parsedData = new ParsedCsvData(); // 读取文件并过滤空行 var allLines = File.ReadAllLines(filePath) .Select(line => line.Trim()) .Where(line => !string.IsNullOrEmpty(line)) .ToList(); int currentLineIndex = 0; while (currentLineIndex < allLines.Count) { var currentLine = allLines[currentLineIndex]; // 匹配不同段落的起始标记 if (currentLine == "[INFO]") { parsedData.Info = ParseInfoSection(allLines, ref currentLineIndex); } else if (currentLine == "[PANEL_INSP_RESULT]") { parsedData.PanelResults = ParsePanelSection(allLines, ref currentLineIndex); } else if (currentLine == "[BOARD_INSP_RESULT]") { parsedData.BoardResults = ParseBoardSection(allLines, ref currentLineIndex); } else if (currentLine == "[COMPONENT_INSP_RESULT]") { parsedData.ComponentResults = ParseComponentSection(allLines, ref currentLineIndex); } else { currentLineIndex++; } } return parsedData; } // 解析INFO段 private static Info ParseInfoSection(List<string> lines, ref int index) { index++; // 跳过[INFO]行 var headers = lines[index++].Split(','); var dataLine = lines[index++].Split(','); index++; // 跳过[INFO_END]行 return new Info { LineName = dataLine[Array.IndexOf(headers, "LINE_NAME")], MachineSn = dataLine[Array.IndexOf(headers, "MACHINE_SN")], MachineName = dataLine[Array.IndexOf(headers, "MACHINE_NAME")], OperatorId = dataLine[Array.IndexOf(headers, "OPERATOR_ID")] }; } // 解析PANEL_INSP_RESULT段 private static List<PanelInspResult> ParsePanelSection(List<string> lines, ref int index) { var results = new List<PanelInspResult>(); index++; // 跳过段头行 var headers = lines[index++].Split(','); // 读取数据直到遇到结束标记 while (index < lines.Count && lines[index] != "[PANEL_INSP_RESULT_END]") { var dataLine = lines[index++].Split(','); if (dataLine.Length != headers.Length) continue; results.Add(new PanelInspResult { ModelName = dataLine[Array.IndexOf(headers, "MODEL_NAME")], ModelCode = dataLine[Array.IndexOf(headers, "MODEL_CODE")], PanelSide = dataLine[Array.IndexOf(headers, "PANEL_SIDE")], Index = int.TryParse(dataLine[Array.IndexOf(headers, "INDEX")], out var idx) ? idx : 0, Barcode = dataLine[Array.IndexOf(headers, "BARCODE")], Date = dataLine[Array.IndexOf(headers, "DATE")], StartTime = dataLine[Array.IndexOf(headers, "START_TIME")], EndTime = dataLine[Array.IndexOf(headers, "END_TIME")], DefectName = dataLine[Array.IndexOf(headers, "DEFECT_NAME")], DefectCode = dataLine[Array.IndexOf(headers, "DEFECT_CODE")], Result = dataLine[Array.IndexOf(headers, "RESULT")] }); } index++; // 跳过_END行 return results; } // 解析BOARD_INSP_RESULT段 private static List<BoardInspResult> ParseBoardSection(List<string> lines, ref int index) { var results = new List<BoardInspResult>(); index++; // 跳过段头行 var headers = lines[index++].Split(','); while (index < lines.Count && lines[index] != "[BOARD_INSP_RESULT_END]") { var dataLine = lines[index++].Split(','); if (dataLine.Length != headers.Length) continue; results.Add(new BoardInspResult { BoardNo = int.TryParse(dataLine[Array.IndexOf(headers, "BOARD_NO")], out var no) ? no : 0, Barcode = dataLine[Array.IndexOf(headers, "BARCODE")], DefectName = dataLine[Array.IndexOf(headers, "DEFECT_NAME")], DefectCode = dataLine[Array.IndexOf(headers, "DEFECT_CODE")], Badmark = dataLine[Array.IndexOf(headers, "BADMARK")], Result = dataLine[Array.IndexOf(headers, "RESULT")] }); } index++; // 跳过_END行 return results; } // 解析COMPONENT_INSP_RESULT段 private static List<ComponentInspResult> ParseComponentSection(List<string> lines, ref int index) { var results = new List<ComponentInspResult>(); index++; // 跳过段头行 var headers = lines[index++].Split(','); while (index < lines.Count && lines[index] != "[COMPONENT_INSP_RESULT_END]") { var dataLine = lines[index++].Split(','); if (dataLine.Length != headers.Length) continue; results.Add(new ComponentInspResult { BoardNo = int.TryParse(dataLine[Array.IndexOf(headers, "BOARD_NO")], out var no) ? no : 0, LocationName = dataLine[Array.IndexOf(headers, "LOCATION_NAME")], PinNumber = dataLine[Array.IndexOf(headers, "PIN_NUMBER")], PosX = dataLine[Array.IndexOf(headers, "POS_X")], PosY = dataLine[Array.IndexOf(headers, "POS_Y")], DefectName = dataLine[Array.IndexOf(headers, "DEFECT_NAME")], DefectCode = dataLine[Array.IndexOf(headers, "DEFECT_CODE")], Result = dataLine[Array.IndexOf(headers, "RESULT")] }); } index++; // 跳过_END行 return results; } }
三、使用示例
在主程序中调用解析器并输出结果:
class Program { static void Main(string[] args) { string csvFilePath = @"C:\YourPath\TargetFile.csv"; // 替换为你的文件路径 var parsedData = SegmentedCsvParser.ParseFile(csvFilePath); // 打印解析结果示例 Console.WriteLine("INFO段数据:"); Console.WriteLine($"生产线名称:{parsedData.Info.LineName}"); Console.WriteLine($"设备序列号:{parsedData.Info.MachineSn}"); Console.WriteLine("\n面板检测结果:"); foreach (var panel in parsedData.PanelResults) { Console.WriteLine($"条码:{panel.Barcode},检测结果:{panel.Result}"); } Console.WriteLine("\n板卡检测结果:"); foreach (var board in parsedData.BoardResults) { Console.WriteLine($"板卡号:{board.BoardNo},条码:{board.Barcode},检测结果:{board.Result}"); } } }
四、注意事项
- 上述为原生C#实现,无需额外依赖,适合新手理解基础解析逻辑。
- 如果需要处理包含逗号、换行符的复杂CSV单元格,推荐使用NuGet包
CsvHelper提升解析效率。 - 代码中加入了
int.TryParse等安全转换逻辑,避免数据格式错误导致程序崩溃。 - 确保程序有目标文件的读取权限,且文件路径配置正确。
内容的提问来源于stack exchange,提问作者Arshad Tigdikar
相关产品推荐
相关产品推荐

