如何在F#中创建CSV文件并写入数据

11

我该如何在F#中创建一个csv文件,并将以下记录类型写入其中?

    type test = { G:array<double>; P:array<double>; GG:array<double>; PP:array<double> } 

    let table = [for x in 0..(Un0.Length - 1) -> 
        let b = Un0.[x] in 
        if b=0.0 then {G=0.0; P=0.0; GG=0.0; PP=0.0}
        else {G=G_0.[x]/b; P=P0.[x]/b; GG=G0.[x]/b; PP=PP0.[x]/b}]
3个回答

24

FSharp.Data的CSV类型提供程序主要用于读取CSV文件(如其名称所示),但也可以很好地编写CSV文件。

您只需要定义类型,可以通过提供样本.CSV文件来实现

let titanic2 = CsvProvider<"../data/Titanic.csv", Schema="Fare=float,PClass->Passenger Class">.GetSample()

或者直接定义架构

type MyCsvType = CsvProvider<Schema = "A (int), B (string), C (date option)", HasHeaders=false>

那么您可以创建一个记录对象并填充它(以类型安全的方式!)

// you can build the rows themselves
let myCsv = new MyCsvType( [ MyCsvType.Row(1, "a", None)
                             MyCsvType.Row(2, "B", Some DateTime.Now) ])

// or, for your scenario, you probably want to define a conversion function
// from your record type to the CSV provider's type
let buildRowFromObject obj = MyCsvType.Row(obj.A, obj.B, obj.C)

let buildTableFromObjects = (Seq.map buildRowFromObject) >> Seq.toList >> MyCsvType

let myCsv = someSequenceOfObjects |> buildTableFromObjects

最后,只需调用即可。

myCsv.SaveToString()

以 CSV 格式获取输出。


3
能否从现有的类型中推断出 csv 格式(一种自动映射/模式定义)的方法? - Răzvan Flavius Panda
这个 CSV 文件应该保存在哪里? - SantiClaus
这个 CSV 文件应该保存在哪里?.SaveToString() 方法返回一个字符串,将其保存到何处取决于调用方。要保存到本地磁盘,请使用 .Save() 函数,它需要一个带有路径的字符串、一个 TextWriter 或一个 Stream 参数,其中将写入内容。请参见: https://github.com/fsharp/FSharp.Data/blob/545c0eb89547e7ad29657bd18ec7a4df3b78c292/src/Csv/CsvRuntime.fs#L315请注意,内部 SaveSaveAsString 使用默认设置创建 StringWriter/StreamWriter,因此使用平台默认换行符。 - kódfodrász

3

记录CSV不必使用F# Data。

我改变了test的定义并添加了一些值,这样您就可以编译:

type test = { G:double; P:double; GG:double; PP:double }
            override this.ToString() = 
                sprintf "%f;%f;%f;%f\n" this.G this.P this.GG this.PP

let G_0  =  [|(0.0)..(10.0)|]
let Un0  =  [|(1.0)..(11.0)|]
let P0   =  [|(2.0)..(12.0)|]
let G0   =  [|(3.0)..(13.0)|]
let PP0  =  [|(4.0)..(14.0)|]

let table = [for x in 0..(Un0.Length - 1) -> 
                let b = Un0.[x] 
                if b=0.0 then {G=0.0; P=0.0; GG=0.0; PP=0.0}
                else {G=G_0.[x]/b; P=P0.[x]/b; GG=G0.[x]/b; PP=PP0.[x]/b}]

let wr = new System.IO.StreamWriter("Csv.csv")
table |> List.map(string) |> String.concat("") |> wr.Write
wr.Close()

结果:

在此输入图片描述


翻译完成。

1
@HaagenDaz,靠近.exe文件。但是您可以指定任何路径:System.IO.StreamWriter(PathToFile)。 - FoggyFinder
我们可以在数组上使用这个,而不是列表吗? - HaagenDaz
1
@HaagenDaz,对于通过索引进行随机访问,数组比列表更快。因此最好使用数组。 - FoggyFinder
1
@FoggyFinder 对于一般的CSV写入,最好使用像FSharp.Data这样的库,因为它会为您处理转义。对于这个特定的数据,如果我们忽略本地化,就没有问题。 - Răzvan Flavius Panda
2
这不是符合RFC 4180标准的CSV文件。例如,它不能处理文本和特殊字符转义。此外,分隔符字符甚至不是逗号。小数点是与语言环境相关的。它可能在您的计算机上与Excel一起使用(Excel有一个臭名昭著的CSV实现),但不会产生可移植的CSV输出。 - kódfodrász
显示剩余10条评论

0

这并不是你问题的确切答案,但它很相似且可能会有用

如何使用F# CSV类型提供程序编辑csv文件

解决方案:

#r "..\packages\FSharp.Data.2.3.3\lib\\net40\FSharp.Data.dll"
open System.IO
open FSharp.Data

type CsvTest = CsvProvider<"""C:\Users\User\Desktop\sample.csv""">
let textReader = File.OpenRead("""C:\Users\User\Desktop\sample.csv""")// need to use TextReader
let csvTest = CsvTest.Load(textReader)
let modified = csvTest.Append [CsvTest.Row(3,"bum") ]// add row to csv
textReader.Close()// closing file before edit...
modified.Save   """C:\Users\User\Desktop\sample.csv""" //save it

如果您正在使用fsx,则可能需要重置交互式会话

说明:

像这样直接加载文件:

let csvTest = CsvTest.Load("""C:\Users\User\Desktop\sample.csv""")

不起作用。如果您尝试,将会出现错误:

System.IO.IOException:“由于另一个进程正在使用该文件'C:\ Users \ User \ Desktop \ sample.csv',因此无法访问该文件。”

所以我使用了可以关闭的TextReader。

也许有更简单的解决方案,但我没有找到任何。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接