我有一个大文件(200K - 300K行文本)。 它几乎但不是一个CSV文件。
列标题位于第二行,其中有一行虚拟文本
在那之前。
有些行散布着实际的数据行。他们有 逗号,但大多数列都是空白的。它们与我无关。
我需要有效地读取这个文件,并解析实际的行 有效,作为CSV数据。
我的第一个想法是编写一个清除第一行的空白程序和空白行,只留下我想要的标题和详细信息 在CsvParser可以读取的CSV文件中。
这很简单,只需从StreamReader读取ReadLine,我可以通过将其视为字符串来保持或忽略每一行。
现在虽然我有一个新问题。
我可以使用有效数据中的一列来忽略更多行。
如果我使用CsvParser阅读已清理的文件,则很容易按该列过滤。
但是,我真的不想浪费把我不需要的行写到Clean文件中。
我希望能够在清理文件时检查该列。但是,在那一点上,我使用代表整行的字符串。要达到我想要的特定栏目并不容易。
我不能分开','其他专栏文本中可能有逗号。 我最终编写了Csv解析逻辑,我首先使用的是CsvParser。
理想情况下,我想读取现有文件,清除我可以基于字符串的行,然后以某种方式使用CsvParser解析生成的seq。
我看到CsvFile可以从Streams和Readers加载,但我不确定这有多大帮助。
有什么建议或者我只是要求太多?我是否应该在加载清理文件时处理额外的过滤?
答案 0 :(得分:1)
您可以直接使用CsvFile
类来避免执行大部分解析工作。
F# Data documentation有一些扩展示例,详细说明如何执行此操作。
在文件开头跳过行由skipRows
参数处理。传递ignoreErrors
参数也会忽略无法解析的行。
open FSharp.Data
let csv = CsvFile.Load(file, skipRows=1, ignoreErrors=true)
for row in csv.Rows do
printfn "%s" row.GetColumn "Name"
如果您必须对行进行更复杂的过滤,那么不需要临时文件的简单方法是过滤File.ReadLines
的结果并将其传递给CsvFile.Parse
。
下面的示例跳过六行前奏,读取行直到它到达空行,使用CsvFile
解析数据,最后将结果行过滤到感兴趣的行。
let tableA =
File.ReadLines(file)
|> Seq.skip(6)
|> Seq.takeWhile(fun l -> String.length l > 0)
|> String.concat "\n"
let csv = CsvFile.Parse(tableA)
for row in csv.Rows.Filter(fun row -> row?Close.AsFloat() > row?Open.AsFloat()) do
printfn "%s" row.GetColumn "Name"