C#读取含额外分隔符的~分隔文本文件时异常的解决方法
解决C#读取含额外分隔符的~分隔文本文件问题
当Excel字段包含分隔符~(如Name列值为~Doe)时,生成的~分隔文本行会变成2000~~Doe~23,使用TextFieldParser读取时会抛出"Input array is longer than the number of columns in this table"异常——原因是字段内的~被误识别为分隔符,导致拆分出的字段数与DataTable列数不匹配。
核心解决思路是生成文本时对含分隔符的字段做转义处理,同时读取时确保解析器能识别被包裹的字段,辅以容错逻辑避免崩溃。
1. 修正生成~分隔文本的逻辑
生成文本时,必须对包含~或双引号的字段用双引号包裹(符合CSV规范),同时转义字段内的双引号(替换为两个双引号),确保解析器能正确识别字段边界。
示例代码:
// 从DataTable生成~分隔的文本文件 private void GenerateDelimitedFile(DataTable data, string outputFilePath) { using (StreamWriter sw = new StreamWriter(outputFilePath, false, Encoding.UTF8)) { // 写入表头 string headerLine = string.Join("~", data.Columns.Cast<DataColumn>() .Select(col => EscapeField(col.ColumnName))); sw.WriteLine(headerLine); // 写入数据行 foreach (DataRow row in data.Rows) { string[] fieldValues = row.ItemArray .Select(item => EscapeField(item?.ToString() ?? string.Empty)) .ToArray(); string dataLine = string.Join("~", fieldValues); sw.WriteLine(dataLine); } } } // 字段转义方法:处理含分隔符或双引号的字段 private static string EscapeField(string value) { if (value.Contains("~") || value.Contains("\"")) { // 转义双引号(替换为""),并用双引号包裹字段 return $"\"{value.Replace("\"", "\"\"")}\""; } return value; }
使用上述代码后,含~Doe的字段会被转义为"~Doe",生成的行变为2000~"~Doe"~23,解析器能正确识别这是三个字段。
2. 优化读取文本的代码
保持TextFieldParser的HasFieldsEnclosedInQuotes=true配置,同时增加容错逻辑,处理可能的字段数不匹配情况:
// 读取~分隔的文本文件到DataTable private DataTable ReadDelimitedFile(string filePath) { DataTable data = new DataTable(); using (TextFieldParser parser = new TextFieldParser(filePath)) { parser.HasFieldsEnclosedInQuotes = true; parser.SetDelimiters("~"); parser.TrimWhiteSpace = false; // 按需设置是否修剪字段前后空格 // 读取表头并创建列 string[] headers = parser.ReadFields(); if (headers != null) { foreach (string header in headers) { data.Columns.Add(header, typeof(string)); } } // 读取数据行 while (!parser.EndOfData) { try { string[] fields = parser.ReadFields(); if (fields == null || data.Columns.Count == 0) continue; // 处理字段数与列数不匹配的情况 string[] adjustedFields = new string[data.Columns.Count]; Array.Copy(fields, adjustedFields, Math.Min(fields.Length, data.Columns.Count)); // 字段数少于列数时,剩余列填充空字符串 for (int i = fields.Length; i < data.Columns.Count; i++) { adjustedFields[i] = string.Empty; } data.Rows.Add(adjustedFields); } catch (MalformedLineException ex) { // 记录错误日志,跳过格式错误的行 Console.WriteLine($"跳过格式错误的行: {ex.Message}"); } } data.AcceptChanges(); } return data; }
关键说明
- 转义是核心:如果生成文本时不做转义,无论读取逻辑怎么优化,都无法区分字段内的分隔符和真正的分隔符。
HasFieldsEnclosedInQuotes=true是必须的:告诉TextFieldParser忽略引号内的分隔符。- 容错逻辑:避免个别格式错误的行导致整个读取任务失败,可根据需求调整错误处理方式(如记录详细日志)。
内容的提问来源于stack exchange,提问作者DevP
相关产品推荐
相关产品推荐

