StringReader.ReadLine逐行读取CSV文件出现内容截断如何解决?
问题根因
- CSV字段内部合法换行被误切割
CSV规范允许被双引号包裹的字段内部包含换行符,这类换行属于字段内容的一部分,不是记录的分隔边界。你直接调用ReadLine()是按物理换行切割内容,会把单条逻辑记录拆成多个片段,最终导致记录解析不完整、内容看起来被截断。这也正好对应你部分文件正常、部分文件异常的现象:没有内部换行的CSV可以正常读取,带内部换行的CSV就会出问题。 - 逐行拼接逻辑丢失换行标记
ReadLine()返回的结果会自动剥离行尾的\r、\n或\r\n,你直接用+=拼接的时候没有补回换行符,最终拼接出来的字符串和原内容结构不一致,也会造成内容被截断的错觉。 - 普通文本读取逻辑不适用于CSV格式
你参考的官方示例是针对无特殊转义规则的普通文本,默认每行对应一条独立记录。而CSV有专属的转义规则,不能直接套用普通文本的逐行读取逻辑。
兼容逐行处理的解决方案
方案1:使用成熟CSV解析库(最推荐)
不要手动处理CSV的边界判断逻辑,直接用业内久经验证的解析库,内置支持带内部换行的字段解析,同时天然支持逐行处理逻辑记录,不需要自己处理底层读取细节,稳定性和兼容性都远高于自行实现的逻辑。
方案2:自行实现支持CSV转义规则的逐行读取
如果必须自己实现读取逻辑,可以参考如下思路处理:
每次读取物理行后,统计当前未闭合的双引号数量,如果为奇数,说明当前物理行属于上一条逻辑记录的一部分,需要补回换行符后和后续内容拼接,直到双引号数量为偶数,才代表一条完整的逻辑记录读取完成。
示例代码如下:
StringBuilder currentRecord = new StringBuilder(); string line; // 直接用ReadLine返回值判空即可,无需额外调用Peek while ((line = stringReader.ReadLine()) != null) { currentRecord.Append(line); // 统计未转义的双引号数量(CSV中""代表转义的单个双引号) string temp = currentRecord.ToString().Replace("\"\"", string.Empty); int unescapedQuoteCount = temp.Count(c => c == '"'); if (unescapedQuoteCount % 2 == 0) { // 完整逻辑记录读取完成,执行你的业务处理逻辑 ProcessRecord(currentRecord.ToString()); currentRecord.Clear(); } else { // 属于字段内部换行,补回被ReadLine移除的换行符 currentRecord.Append(Environment.NewLine); } }
方案3:确认无内部换行场景的简化方案
如果你能确认所有待处理的CSV都不存在引号包裹的内部换行,只是原有逻辑有缺陷,可以直接修正为如下写法:
StringBuilder resultBuilder = new StringBuilder(); string line; while ((line = stringReader.ReadLine()) != null) { // 此处执行你的逐行业务处理逻辑 ProcessLine(line); // 如果需要拼接完整内容,调用AppendLine补回换行 resultBuilder.AppendLine(line); } string results = resultBuilder.ToString();
相较于你原来的写法,该方案用StringBuilder替代字符串直接拼接提升性能,同时补回了行尾换行符,用ReadLine返回值判空的逻辑也比额外调用Peek更简洁可靠。
内容的提问来源于stack exchange,提问作者Captain
相关产品推荐
相关产品推荐

