C#如何仅读取CSV文件中属于指定列名列表的对应列数据
实现方案
基础实现(手动映射,性能最优)
先构建CSV列名到下标的映射字典,完全避免硬编码下标,适配CSV列顺序变化的场景,代码如下:
using System.Globalization; using System.Collections.Generic; using System.IO; // 原有读取colHeads的逻辑保留 List<string> colHeads = new List<string>(); string[] headLines = File.ReadAllLines(@"C:\DATA\MLData\colHeads.txt"); foreach (string line in headLines) { string[] spl = line.Split('='); colHeads.Add(spl[0].Trim()); } // 读取CSV文件逻辑 string[] csvLines = File.ReadAllLines(@"C:\DATA\MLData\hist.csv"); if (csvLines.Length == 0) return; // 构建列名→列索引的映射字典,仅保留colHeads中存在的列 Dictionary<string, int> colIndexMap = new Dictionary<string, int>(); string[] csvHeaders = csvLines[0].Split(','); for (int i = 0; i < csvHeaders.Length; i++) { string currentCol = csvHeaders[i].Trim(); if (colHeads.Contains(currentCol)) { colIndexMap[currentCol] = i; } } List<Record> resultList = new List<Record>(); // 跳过表头行,从第二行开始遍历数据 for (int i = 1; i < csvLines.Length; i++) { string[] fields = csvLines[i].Split(','); var rec = new Record(); // 按列名从映射中取对应下标取值 if (colIndexMap.TryGetValue("Name", out int nameIdx)) rec.Name = fields[nameIdx].Trim(); if (colIndexMap.TryGetValue("ident", out int identIdx)) rec.ident = float.Parse(fields[identIdx], CultureInfo.InvariantCulture); if (colIndexMap.TryGetValue("location", out int locIdx)) rec.location = float.Parse(fields[locIdx], CultureInfo.InvariantCulture); // 其余需要读取的列按相同规则补充即可 resultList.Add(rec); }
自动赋值实现(反射适配多列场景)
如果需要读取的列数较多,不想手动编写重复的赋值代码,可以用反射自动匹配Record类属性和列名:
// 上述构建colIndexMap的逻辑保留,替换数据行遍历逻辑即可 using System.Reflection; var recordProperties = typeof(Record).GetProperties() .ToDictionary(p => p.Name, p => p); List<Record> resultList = new List<Record>(); for (int i = 1; i < csvLines.Length; i++) { string[] fields = csvLines[i].Split(','); var rec = new Record(); foreach (var (colName, colIndex) in colIndexMap) { if (recordProperties.TryGetValue(colName, out PropertyInfo prop)) { var value = Convert.ChangeType(fields[colIndex].Trim(), prop.PropertyType, CultureInfo.InvariantCulture); prop.SetValue(rec, value); } } resultList.Add(rec); }
注意事项
- 直接使用
Split(',')仅适用于字段不含逗号、引号的简单CSV格式,如果CSV存在逗号包裹的字段、转义字符等复杂格式,建议使用专用CSV解析组件处理,避免字段拆分错误。 - 代码中增加了列存在性校验,即使CSV调整列顺序、缺少指定列也不会直接抛出下标越界异常。
内容的提问来源于stack exchange,提问作者user2096512
相关产品推荐
相关产品推荐

