我使用CSV阅读器,发现解析数据需要花费大量时间。如何将整个csv文件加载到内存中,然后按记录处理它,因为我必须对记录进行自定义映射。
TextReader tr = new StreamReader(File.Open(@"C:\MarketData\" + symbol + ".txt", FileMode.Open));
CsvReader csvr = new CsvReader(tr);
while (csvr.Read())
{
// do your magic
}
答案 0 :(得分:4)
创建一个完全代表/镜像CSV文件的类。然后将所有内容读入该类的列表中。以下片段来自CsvHelper的文档。
W = tf.tile(W,tf.constant([1,3]))
重要的部分是.ToList(),因为这会强制将所有数据加载到列表中,而不是在访问时产生结果。
然后,您可以在该列表中执行其他映射/提取,这将在内存中。
如果您已经这样做了,您可以将csv加载到HashSet而不是List(ToHashSet())中。见HashSet vs List Performance
答案 1 :(得分:0)
直接回答您的问题:您可以将文件完全加载到内存流中,然后使用CsvReader从该流重新读取。类似地,您可以为文件流创建更大的读取缓冲区,例如15MB,这将在一次命中中将整个文件读入缓冲区。我怀疑其中任何一个都会真正提高10MB文件的性能。
找出真正的性能瓶颈:从磁盘读取文件内容的时间,将CSV解析为字段的时间,或处理记录的时间?一个10MB的文件看起来很小。我使用自定义csv阅读器处理250MB + csv文件集,没有任何投诉。
如果处理是瓶颈并且您有多个线程可用并且您的csv文件格式不需要支持转义换行符,那么您可以将整个文件读入行列表(System.IO.File.ReadAllLines /。 ReadLines)并使用不同的任务解析每一行。例如:
System.IO.File.ReadLines()
.Skip(1) // header line. Assume trusted to be correct.
.AsParallel()
.Select(ParseRecord) // RecordClass ParseRecord(string line)
.ForAll(ProcessRecord); // void ProcessRecord(RecordClass)
如果要解析许多文件,可以在不同的任务中处理每个文件,并使用异步方法来最大化吞吐量。如果它们都来自同一个物理磁盘,那么你的milage会有所不同,甚至可能比单线程方法更差。
更高级:
如果您知道您的文件只包含8位字符,那么您可以对字节数组进行操作并跳过StreamReader开销将字节转换为字符。这样,您可以在单个调用中将整个文件读取为字节数组,并扫描换行符,前提是不需要支持换行符。在这种情况下,可以通过多个线程扫描换行符,每个线程都查看字节数组的一部分。
如果您不需要支持字段转义(a," b,c",d),那么您可以编写更快的解析器,只需查找字段分隔符(通常为逗号)。您还可以将字段分界解析和字段内容解析拆分为线程,如果这是一个瓶颈,尽管内存访问位置可能会否定任何好处。
在某些情况下,您可能不需要将字段解析为中间数据结构(例如双精度数,字符串),并且可以直接处理对字段开头/结尾的引用,并节省一些中间数据结构的创建。