我需要导入一个大文本文件 (55MB) (525000 * 25) 并操作数据并产生一些输出。像往常一样,我开始使用 f# Interactive 进行探索,并且得到了一些非常奇怪的行为。
这个文件太大还是我的代码错误?
第一个测试是导入并简单地计算一列的总和(不是最终目标,而是第一个测试):
let calctest =
let reader = new StreamReader(path)
let csv = reader.ReadToEnd()
csv.Split([|'\n'|])
|> Seq.skip 1
|> Seq.map (fun line -> line.Split([|','|]))
|> Seq.filter (fun a -> a.[11] = "M")
|> Seq.map (fun values -> float(values.[14]))
正如预期的那样,这会在类型检查和交互中产生一个浮点序列。如果我知道添加:
|> Seq.sum
类型检查有效,并表示该函数应该返回一个 float ,但如果我在交互式模式下运行它,则会收到此错误:
System.IndexOutOfRangeException: Index was outside the bounds of the array
然后我再次删除了最后一行,并认为我查看了文本文件中 float 的 seq:
let writetest =
let str = calctest |> Seq.map (fun i -> i.ToString())
System.IO.File.WriteAllLines("test.txt", str )
同样,这通过了类型检查,但在交互中抛出错误。
标准 StreamReader 无法处理那么多数据吗?或者我在某个地方出错了?我应该使用与 Streamreader 不同的函数吗? 谢谢。
最佳答案
Seq
是惰性的,这意味着只有当您添加 Seq.sum
时,所有映射和过滤才会真正完成,这就是为什么您看不到添加该行之前出错。您确定所有行上都有 15 列吗?应该是这个问题
我建议您使用 CSV Type Provider而不是仅仅执行 string.Split
,这样您就可以确保不会出现意外的 IndexOutOfRangeException,并且您将正确处理 ,
转义。
此外,您通过调用 reader.ReadToEnd()
将整个 csv 文件读入内存,如果您将 Cache
参数设置为 false,CsvProvider 支持流式传输。对于 55MB 的文件来说这不是问题,但如果您有更大的文件,则可能会出现问题
关于f# - 处理大型文本文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19361281/