2

我需要导入一个大文本文件 (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

类型检查有效,并说这个函数应该返回一个浮点数,但是如果我以交互方式运行它,我会收到这个错误:

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 不同的功能吗?谢谢。

4

1 回答 1

4

Seq是懒惰的,这意味着只有当您添加时,Seq.sum所有映射和过滤才会真正完成,这就是为什么您在添加该行之前看不到错误的原因。您确定所有行都有 15 列吗?这大概就是问题所在

我建议您使用CSV 类型提供程序,而不是仅仅执行 a string.Split,这样您就可以确保不会出现意外的 IndexOutOfRangeException,并且您可以,正确处理转义。

另外,您正在通过调用将整个 csv 文件读入内存,如果您将参数设置为 false reader.ReadToEnd(),则 CsvProvider 支持流式传输。Cache55MB 的文件不是问题,但如果你有更大的文件,它可能会

于 2013-10-14T13:57:21.077 回答