如何在C#/PowerShell中处理7GB大CSV:移除字段内换行并拆分
处理带字段内换行的大型CSV拆分与换行符移除方案
C# 解决方案
使用.NET自带的TextFieldParser(来自Microsoft.VisualBasic程序集)流式解析CSV,它能自动识别带引号包裹的字段,正确处理字段内的换行符,同时避免一次性加载整个文件导致内存溢出。以下是完整实现:
using Microsoft.VisualBasic.FileIO; using System.IO; using System.Linq; public void SplitAndCleanLargeCsv(string inputFilePath, string outputDirectory, int batchSize) { Directory.CreateDirectory(outputDirectory); int recordCount = 0; int fileIndex = 0; StreamWriter currentWriter = null; string[] headers = null; try { using (TextFieldParser parser = new TextFieldParser(inputFilePath)) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); parser.HasFieldsEnclosedInQuotes = true; // 核心配置:识别带引号的字段,处理内部换行 parser.TrimWhiteSpace = false; // 保留字段原始格式,按需调整 // 读取表头行 headers = parser.ReadFields(); if (headers == null) return; while (!parser.EndOfData) { try { // 读取完整的一条记录(自动处理字段内换行) string[] fields = parser.ReadFields(); if (fields == null) break; // 移除每个字段内的换行符(替换为空格,可按需改为空字符串) for (int i = 0; i < fields.Length; i++) { if (!string.IsNullOrEmpty(fields[i])) { fields[i] = fields[i].Replace("\r\n", " ").Replace("\n", " ").Replace("\r", " "); } } // 每batchSize条记录新建一个输出文件 if (recordCount % batchSize == 0) { currentWriter?.Dispose(); string outputPath = Path.Combine(outputDirectory, $"output_{fileIndex}.csv"); currentWriter = new StreamWriter(outputPath); // 写入转义后的表头(处理表头中的引号) currentWriter.WriteLine(string.Join(",", headers.Select(h => $"\"{h.Replace("\"", "\"\"")}\""))); fileIndex++; } // 写入转义后的记录,避免CSV格式错误 string line = string.Join(",", fields.Select(f => string.IsNullOrEmpty(f) ? "" : $"\"{f.Replace("\"", "\"\"")}\"")); currentWriter.WriteLine(line); recordCount++; } catch (MalformedLineException ex) { // 处理格式错误的行,可添加日志记录 System.Console.WriteLine($"跳过格式异常行:{ex.Message}"); } } } } finally { currentWriter?.Dispose(); } }
注意事项
- 需要引用
Microsoft.VisualBasic程序集:.NET Framework可直接添加引用,.NET Core/.NET 5+可通过NuGet安装Microsoft.VisualBasic包 - 换行符替换规则可根据需求调整,例如替换为
""删除换行 - 代码自动处理字段内的引号转义(用
""表示单个"),保证输出CSV格式合法
PowerShell 解决方案
手动处理带引号字段的换行拼接,流式读写避免内存溢出,同时移除字段内的换行符:
$inputPath = "C:\largefile.csv" $outputDir = "C:\split_csv_output" $batchSize = 10000 # 创建输出目录 if (-not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir | Out-Null } $reader = New-Object System.IO.StreamReader($inputPath) $header = $reader.ReadLine() $recordCount = 0 $fileIndex = 0 $writer = $null try { while ($line = $reader.ReadLine()) { # 拼接字段内换行的不完整记录:通过引号数量判断是否为完整行 $quoteCount = ($line | Select-String '"' -AllMatches).Count while ($quoteCount % 2 -ne 0) { $nextLine = $reader.ReadLine() if (-not $nextLine) break $line += "`n$nextLine" $quoteCount += ($nextLine | Select-String '"' -AllMatches).Count } # 将单行记录转为对象 $record = $line | ConvertFrom-Csv -Header ($header -split ',') # 移除每个字段内的换行符 foreach ($prop in $record.PSObject.Properties) { if ($prop.Value -is [string]) { $prop.Value = $prop.Value -replace "`r`n|`n|`r", " " } } # 每batchSize条记录新建输出文件 if ($recordCount % $batchSize -eq 0) { if ($writer) { $writer.Close(); $writer.Dispose() } $outputPath = Join-Path $outputDir "smallfile_$fileIndex.csv" $writer = New-Object System.IO.StreamWriter($outputPath) $writer.WriteLine($header) $fileIndex++ } # 将处理后的记录转为CSV行并写入 $csvLine = $record | ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1 $writer.WriteLine($csvLine) $recordCount++ } } finally { # 释放资源 if ($writer) { $writer.Close(); $writer.Dispose() } $reader.Close(); $reader.Dispose() }
注意事项
- 通过引号数量判断是否为完整记录,解决
ReadLine拆分字段内换行的问题 - 流式处理逐行读写,不会加载整个7GB文件到内存
- 换行符替换可通过修改正则表达式调整规则
内容的提问来源于stack exchange,提问作者404
相关产品推荐
相关产品推荐

