【发布时间】:2021-03-10 18:36:32
【问题描述】:
原始问题 - CSV 文件太大 (700k) 记录 - 因此希望从那个大 CSV 文件创建更小的 CSV 文件。
得到以下代码来剖析文件并创建更小的文件。
private async Task SplitFile(List<CsvRow> rows, string name)
{
var numRows = 30000;
var remainder = rows.Count() % numRows;
var chunks = rows.Count() / numRows;
if (remainder > 0)
{
chunks++;
}
// Iterate rows in chunks
for (var row = 0; row < chunks; row++)
{
// Extract chunks using LINQ
var fileRows = rows
.Skip(row * numRows)
.Take(numRows)
.ToList();
var outputPath = Path.Combine(@"c:\", $"file{row}.txt");
var encoding = new UTF8Encoding(true);
await using var mem = new MemoryStream();
await using var fileWriter = new StreamWriter(outputPath, false, encoding);
await using var writer = new StreamWriter(mem, encoding);
await using var csvBlob = new CsvWriter(writer, CultureInfo.InvariantCulture);
await using var csvFile = new CsvWriter(fileWriter, CultureInfo.InvariantCulture);
await csvFile.WriteRecordsAsync(fileRows);
await csvBlob.WriteRecordsAsync(fileRows);
FileStream file = new FileStream(@$"c:\memfile{row}.txt", FileMode.Create,
FileAccess.Write);
mem.WriteTo(file);
file.Close();
}
}
Blocker - 我正在从 Azure Blob 容器下载原始大文件,并在创建小块后将它们上传回 Blob 容器。为此,我需要将数据保存在 MemoryStreams 中。
我创建物理文件只是为了解决内存流问题。更容易调试。
当我运行上面的代码时 - 小块文件被创建。你会注意到我正在创建两组文件(块)
首先,直接将数据写入File Stream,其次,使用我创建的MemoryStream。
我在通过直接写入文件流创建的文件中获得 30000 条记录,但在第二个文件中我只获得 29889 条记录。
我尝试了所有方法,但在使用 MemoryStream 时无法立即获取所有 30000 条记录。
我刷新了流,摆弄了编码,但没有任何帮助。我读到了带有 BOM 的 UTF8。看起来很有希望,但又无法解决。
我使用的是 Dot Net Core 3.1
MemoryStream 是否存在已知问题。为什么它丢失了最后几条记录?其余文件相同。
有什么想法吗?
谢谢
【问题讨论】:
-
在调用 WriteRecordsAsync 之后、复制到输出文件之前尝试调用 csvBlob.Flush()。我怀疑 CsvWriter 维护一个需要刷新到 MemoryStream 的内部缓冲区,这可能会在您调用 Close/Dispose 时发生。但是,直到您复制内存流之后才会进行处置,因此当您复制到输出文件时,csv 数据不会完全刷新到内存流中。
-
几乎所有 I/O 对象都包含缓冲,并且在尝试使用它们正在写入的其他对象之前未能刷新和/或关闭此类对象将导致数据被截断。查看重复项。
标签: c# csv .net-core memorystream csvhelper