如何用CSVHelper 28.0.1读写动态列CSV至嵌套字典?
用CSVHelper 28.0.1实现动态列CSV的读写(映射为嵌套字典)
针对第一列为Key、其余列数量动态变化的CSV,要实现读写并映射为Dictionary<string, Dictionary<string, string>>类型的查找表,无需定义固定实体类,直接用CSVHelper的基础API即可完成,以下是具体实现:
一、读取CSV到嵌套字典
核心逻辑:先读取所有表头,逐行解析时将第一列值作为外层字典的Key,其余列的表头与对应值组成内层字典。
using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using CsvHelper; using CsvHelper.Configuration; public static Dictionary<string, Dictionary<string, string>> ReadCsvToLookupTable(string filePath) { var config = new CsvConfiguration(CultureInfo.InvariantCulture) { TrimOptions = TrimOptions.Trim, AllowComments = false // 可根据实际CSV格式添加配置,如分隔符、引号规则等 }; var lookupTable = new Dictionary<string, Dictionary<string, string>>(); using (var reader = new StreamReader(filePath)) using (var csv = new CsvReader(reader, config)) { csv.Read(); csv.ReadHeader(); var headers = csv.HeaderRecord; // 提取除Key列外的所有表头 var valueHeaders = headers.Skip(1).ToList(); while (csv.Read()) { var key = csv.GetField<string>(headers[0]); var innerDict = new Dictionary<string, string>(); foreach (var header in valueHeaders) { innerDict[header] = csv.GetField<string>(header); } lookupTable[key] = innerDict; } } return lookupTable; }
二、将修改后的嵌套字典写回CSV
核心逻辑:先收集所有需写入的表头(含Key列和所有内层字典中出现的表头),再按表头顺序逐行写入数据,确保所有列都被覆盖。
public static void WriteLookupTableToCsv(string filePath, Dictionary<string, Dictionary<string, string>> lookupTable) { if (lookupTable == null || !lookupTable.Any()) return; var config = new CsvConfiguration(CultureInfo.InvariantCulture) { TrimOptions = TrimOptions.Trim, ShouldQuote = (field, context) => true // 强制给字段加引号,避免特殊字符干扰 }; // 收集所有唯一表头:先添加Key列,再合并内层字典的键并去重 var allHeaders = new List<string> { "Key" }; // 若CSV的Key列名不是"Key",需对应修改 foreach (var innerDict in lookupTable.Values) { allHeaders.AddRange(innerDict.Keys.Except(allHeaders)); } using (var writer = new StreamWriter(filePath)) using (var csv = new CsvWriter(writer, config)) { // 写入表头 foreach (var header in allHeaders) { csv.WriteField(header); } csv.NextRecord(); // 逐行写入数据 foreach (var kvp in lookupTable) { csv.WriteField(kvp.Key); // 按表头顺序匹配值,无对应值则写空字符串 foreach (var header in allHeaders.Skip(1)) { kvp.Value.TryGetValue(header, out var value); csv.WriteField(value ?? string.Empty); } csv.NextRecord(); } } }
三、使用示例
// 读取CSV文件 var lookupTable = ReadCsvToLookupTable("source.csv"); // 修改数据示例 lookupTable["Key1"]["Header2"] = "UpdatedValue"; lookupTable["Key4"] = new Dictionary<string, string> { { "Header5", "NewData" } }; // 写回修改后的CSV WriteLookupTableToCsv("updated_source.csv", lookupTable);
注意事项
- 若CSV的Key列名不是"Key",需同步修改读取时的
headers[0]引用,以及写入时allHeaders的初始值。 - 可根据实际CSV格式调整
CsvConfiguration参数,比如自定义分隔符、处理空行规则等。 - 处理大体积CSV时,上述流式读写的方式已优化内存占用,无需额外调整。
内容的提问来源于stack exchange,提问作者sdrest
相关产品推荐
相关产品推荐

