我需要导入一个大文本文件(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]))
正如预期的那样,这会在typecheck和交互式中产生一系列浮动。如果我知道添加:
|> 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吗? 谢谢。
答案 0 :(得分:4)
Seq
是懒惰的,这意味着只有在添加Seq.sum
时才会实际执行所有映射和过滤,这就是为什么在添加该行之前没有看到错误的原因。您确定所有行都有15列吗?这可能是问题
我建议您使用CSV Type Provider而不是仅使用string.Split
,这样您就不会有意外的IndexOutOfRangeException,并且您将处理,
正确逃避。
另外,您通过调用reader.ReadToEnd()
将整个csv文件读入内存,如果将Cache
参数设置为false,则CsvProvider支持流式传输。对于55MB文件来说这不是问题,但是如果你有更大的东西,它可能是