使用大文本文件?

时间:2013-10-14 13:24:13

标签: f#

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

1 个答案:

答案 0 :(得分:4)

Seq是懒惰的,这意味着只有在添加Seq.sum时才会实际执行所有映射和过滤,这就是为什么在添加该行之前没有看到错误的原因。您确定所有行都有15列吗?这可能是问题

我建议您使用CSV Type Provider而不是仅使用string.Split,这样您就不会有意外的IndexOutOfRangeException,并且您将处理,正确逃避。

另外,您通过调用reader.ReadToEnd()将整个csv文件读入内存,如果将Cache参数设置为false,则CsvProvider支持流式传输。对于55MB文件来说这不是问题,但是如果你有更大的东西,它可能是