【发布时间】:2019-02-17 12:13:10
【问题描述】:
我正在开发一项服务,该服务将从在线资源中收集大型 CSV 文件,然后在下载时读取这些行(最好是分批),然后将它们发送到数据库。这在任何时候都不应使用超过 256MB 的 RAM,并且不应将文件保存到磁盘。
这是一项每 7 天运行一次的服务,并收集挪威公司登记册中的所有公司(一个漂亮的 250MB 110 万行 CSV 文件可在此处找到:http://hotell.difi.no/download/brreg/enhetsregisteret)
我的应用程序可以轻松下载文件并将其添加到列表,并对其进行处理,但它使用 3.3 GB 的 RAM
public async Task<bool> CollectAndUpdateNorwegianCompanyRegistry()
{
var request = await _httpClient.GetAsync(_options.Value.Urls["BrregCsv"]);
request.EnsureSuccessStatusCode();
using (var stream = await request.Content.ReadAsStreamAsync())
using (var streamReader = new StreamReader(stream))
{
while (!streamReader.EndOfStream)
{
using (var csv = new CsvReader(streamReader)) // CsvReader is from the CsvHelper -nuget
{
csv.Configuration.Delimiter = ";";
csv.Configuration.BadDataFound = null;
csv.Configuration.RegisterClassMap<NorwegianCompanyClassMap>();
await _sqlRepository.UpdateNorwegianCompaniesTable(csv.GetRecords<NorwegianCompany>().ToList());
}
}
}
return true;
}
关于 SqlRepository 的小说明:我已经用一个简单的“破坏者”方法替换了它,它只是清除数据,以便在调试时不使用任何额外的资源
我希望垃圾收集器会“销毁”处理文件行时使用的资源,但事实并非如此。
简单地说,我希望发生以下情况: 当 CSV 下载时,它会读取几行,然后将它们发送到一个方法,然后刷新内存中的行
我在处理大型数据集方面确实缺乏经验,所以我正在处理其他人的工作,并没有得到我期望的结果
感谢您的时间和帮助
【问题讨论】:
-
代码读取所有行并将对象放入列表中。任何垃圾收集都不可能发生。什么是 CsvReader?不使用 ToList 时返回什么?
-
@SamiKuhmonen CsvReader.GetRecords() 返回一个通用的 Enumerable。它只是一个辅助库,用于简化 CSV 数据的映射,(joshclose.github.io/CsvHelper)
-
那么您应该能够使用可枚举而不将其放入列表中,并以最少的内存使用逐个对象处理数据对象。您只需要让存储库使用可枚举而不是列表来处理事物。
标签: c# csv stream large-files