CSV writer

A simple CSV writer implementation as two type extensions for the Seq module. Use it with Records, Classes and Tuples. Have a look at the modified CSV reader sample from Don Symes Expert F# too http://fssnip.net/3T in order to advance this snippet using the ColumnAttribute

Copy Source
Copy Link
Tools:
 1: module Csv
 2: 
 3: open System.IO
 4: open Microsoft.FSharp.Reflection
 5: 
 6: type Array =
 7:     static member join delimiter xs = 
 8:         xs 
 9:         |> Array.map (fun x -> x.ToString())
10:         |> String.concat delimiter
11: 
12: type Seq =
13:     static member write (path:string) (data:seq<'a>): 'result = 
14:         use writer = new StreamWriter(path)
15:         data
16:         |> Seq.iter writer.WriteLine 
17: 
18:     static member csv (separator:string) (headerMapping:string -> string) ( data:seq<'a>) =
19:         seq {
20:             let dataType = typeof<'a>
21: 
22:             let header = 
23:                 match dataType with
24:                 | ty when FSharpType.IsRecord ty ->
25:                     FSharpType.GetRecordFields dataType
26:                     |> Array.map (fun info -> headerMapping info.Name)                    
27:                 | ty when FSharpType.IsTuple ty -> 
28:                     FSharpType.GetTupleElements dataType
29:                     |> Array.mapi (fun idx info -> headerMapping(string idx) )
30:                 | _ -> dataType.GetProperties()
31:                        |> Array.map (fun info -> headerMapping info.Name)
32: 
33:             yield header |> Array.join separator
34:                                     
35:             let lines =
36:                 match dataType with 
37:                 | ty when FSharpType.IsRecord ty -> 
38:                     data |> Seq.map FSharpValue.GetRecordFields
39:                 | ty when FSharpType.IsTuple ty ->
40:                     data |> Seq.map FSharpValue.GetTupleFields
41:                 | _ -> 
42:                     let props = dataType.GetProperties()
43:                     data |> Seq.map ( fun line -> 
44:                               props |> Array.map ( fun prop ->
45:                                 prop.GetValue(line, null) ))                                     
46: 
47:             yield! lines |> Seq.map (Array.join separator)        
48:         }
49: //Example
50: type Test(colA:string, colB:int) = 
51:     member x.ColA = colA
52:     member x.ColB = colB
53: 
54: let testData = seq { for i in 1..10 -> new Test("col"+string(i), i) }
55: 
56: // using all public class properties for serialization
57: testData
58: |> Seq.csv "\t" (fun propertyName -> propertyName)
59: |> Seq.write "test_with_class_properties.csv"
60: 
61: // using a tuple projection
62: testData
63: |> Seq.distinctBy (fun testInstance -> testInstance.ColA)  
64: |> Seq.map (fun probe -> (probe.ColB) )
65: |> Seq.csv "\t" (fun columnName -> 
66:                     match columnName with 
67:                     | "0" -> "ColB"
68:                     | _ -> columnName)
69: |> Seq.write "test_with_tuple_projection.csv"
module Csv
namespace System
namespace System.IO
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Reflection
Multiple items
module Array

from Microsoft.FSharp.Collections

--------------------

type Array =
  class
    static member join : delimiter:string -> xs:'a [] -> string
  end

Full name: Csv.Array
static member Array.join : delimiter:string -> xs:'a [] -> string

Full name: Csv.Array.join
val delimiter : string

  type: string
  implements: System.IComparable
  implements: System.ICloneable
  implements: System.IConvertible
  implements: System.IComparable<string>
  implements: seq<char>
  implements: System.Collections.IEnumerable
  implements: System.IEquatable<string>
val xs : 'a []

  type: 'a []
  implements: System.ICloneable
  implements: System.Collections.IList
  implements: System.Collections.ICollection
  implements: System.Collections.IStructuralComparable
  implements: System.Collections.IStructuralEquatable
  implements: System.Collections.Generic.IList<'a>
  implements: System.Collections.Generic.ICollection<'a>
  implements: seq<'a>
  implements: System.Collections.IEnumerable
  inherits: System.Array
val map : ('T -> 'U) -> 'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val x : 'a
System.Object.ToString() : string
module String

from Microsoft.FSharp.Core
val concat : string -> seq<string> -> string

Full name: Microsoft.FSharp.Core.String.concat
Multiple items
module Seq

from Microsoft.FSharp.Collections

--------------------

type Seq =
  class
    static member csv : separator:string -> headerMapping:(string -> string) -> data:seq<'a> -> seq<string>
    static member write : path:string -> data:seq<'a> -> unit
  end

Full name: Csv.Seq
static member Seq.write : path:string -> data:seq<'a> -> unit

Full name: Csv.Seq.write
val path : string

  type: string
  implements: System.IComparable
  implements: System.ICloneable
  implements: System.IConvertible
  implements: System.IComparable<string>
  implements: seq<char>
  implements: System.Collections.IEnumerable
  implements: System.IEquatable<string>
Multiple items
val string : 'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------

type string = System.String

Full name: Microsoft.FSharp.Core.string

  type: string
  implements: System.IComparable
  implements: System.ICloneable
  implements: System.IConvertible
  implements: System.IComparable<string>
  implements: seq<char>
  implements: System.Collections.IEnumerable
  implements: System.IEquatable<string>
val data : seq<'a>

  type: seq<'a>
  inherits: System.Collections.IEnumerable
Multiple items
val seq : seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------

type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>

  type: seq<'T>
  inherits: System.Collections.IEnumerable
val writer : StreamWriter

  type: StreamWriter
  implements: System.IDisposable
  inherits: TextWriter
  inherits: System.MarshalByRefObject
type StreamWriter =
  class
    inherit System.IO.TextWriter
    new : System.IO.Stream -> System.IO.StreamWriter
    new : System.IO.Stream * System.Text.Encoding -> System.IO.StreamWriter
    new : System.IO.Stream * System.Text.Encoding * int -> System.IO.StreamWriter
    new : string -> System.IO.StreamWriter
    new : string * bool -> System.IO.StreamWriter
    new : string * bool * System.Text.Encoding -> System.IO.StreamWriter
    new : string * bool * System.Text.Encoding * int -> System.IO.StreamWriter
    member AutoFlush : bool with get, set
    member BaseStream : System.IO.Stream
    member Close : unit -> unit
    member Encoding : System.Text.Encoding
    member Flush : unit -> unit
    member Write : char -> unit
    member Write : char [] -> unit
    member Write : string -> unit
    member Write : char [] * int * int -> unit
    static val Null : System.IO.StreamWriter
  end

Full name: System.IO.StreamWriter

  type: StreamWriter
  implements: System.IDisposable
  inherits: TextWriter
  inherits: System.MarshalByRefObject
val iter : ('T -> unit) -> seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
Multiple overloads
TextWriter.WriteLine() : unit
TextWriter.WriteLine(value: obj) : unit
TextWriter.WriteLine(value: string) : unit
TextWriter.WriteLine(value: decimal) : unit
TextWriter.WriteLine(value: float) : unit
TextWriter.WriteLine(value: float32) : unit
TextWriter.WriteLine(value: uint64) : unit
TextWriter.WriteLine(value: int64) : unit
TextWriter.WriteLine(value: uint32) : unit
TextWriter.WriteLine(value: int) : unit
   (+8 other overloads)
static member Seq.csv : separator:string -> headerMapping:(string -> string) -> data:seq<'a> -> seq<string>

Full name: Csv.Seq.csv
val separator : string

  type: string
  implements: System.IComparable
  implements: System.ICloneable
  implements: System.IConvertible
  implements: System.IComparable<string>
  implements: seq<char>
  implements: System.Collections.IEnumerable
  implements: System.IEquatable<string>
val headerMapping : (string -> string)
val dataType : System.Type

  type: System.Type
  implements: System.Reflection.ICustomAttributeProvider
  implements: System.Runtime.InteropServices._MemberInfo
  implements: System.Runtime.InteropServices._Type
  implements: System.Reflection.IReflect
  inherits: System.Reflection.MemberInfo
val typeof<'T> : System.Type

Full name: Microsoft.FSharp.Core.Operators.typeof
val header : string []

  type: string []
  implements: System.ICloneable
  implements: System.Collections.IList
  implements: System.Collections.ICollection
  implements: System.Collections.IStructuralComparable
  implements: System.Collections.IStructuralEquatable
  implements: System.Collections.Generic.IList<string>
  implements: System.Collections.Generic.ICollection<string>
  implements: seq<string>
  implements: System.Collections.IEnumerable
  inherits: System.Array
val ty : System.Type

  type: System.Type
  implements: System.Reflection.ICustomAttributeProvider
  implements: System.Runtime.InteropServices._MemberInfo
  implements: System.Runtime.InteropServices._Type
  implements: System.Reflection.IReflect
  inherits: System.Reflection.MemberInfo
type FSharpType =
  class
    static member GetExceptionFields : exceptionType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> System.Reflection.PropertyInfo []
    static member GetFunctionElements : functionType:System.Type -> System.Type * System.Type
    static member GetRecordFields : recordType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> System.Reflection.PropertyInfo []
    static member GetTupleElements : tupleType:System.Type -> System.Type []
    static member GetUnionCases : unionType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> UnionCaseInfo []
    static member IsExceptionRepresentation : exceptionType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> bool
    static member IsFunction : typ:System.Type -> bool
    static member IsModule : typ:System.Type -> bool
    static member IsRecord : typ:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> bool
    static member IsTuple : typ:System.Type -> bool
    static member IsUnion : typ:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> bool
    static member MakeFunctionType : domain:System.Type * range:System.Type -> System.Type
    static member MakeTupleType : types:System.Type [] -> System.Type
  end

Full name: Microsoft.FSharp.Reflection.FSharpType
static member FSharpType.IsRecord : typ:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> bool
static member FSharpType.GetRecordFields : recordType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> System.Reflection.PropertyInfo []
val info : System.Reflection.PropertyInfo

  type: System.Reflection.PropertyInfo
  implements: System.Reflection.ICustomAttributeProvider
  implements: System.Runtime.InteropServices._MemberInfo
  implements: System.Runtime.InteropServices._PropertyInfo
  inherits: System.Reflection.MemberInfo
property System.Reflection.MemberInfo.Name: string
static member FSharpType.IsTuple : typ:System.Type -> bool
static member FSharpType.GetTupleElements : tupleType:System.Type -> System.Type []
val mapi : (int -> 'T -> 'U) -> 'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.mapi
val idx : int

  type: int
  implements: System.IComparable
  implements: System.IFormattable
  implements: System.IConvertible
  implements: System.IComparable<int>
  implements: System.IEquatable<int>
  inherits: System.ValueType
val info : System.Type

  type: System.Type
  implements: System.Reflection.ICustomAttributeProvider
  implements: System.Runtime.InteropServices._MemberInfo
  implements: System.Runtime.InteropServices._Type
  implements: System.Reflection.IReflect
  inherits: System.Reflection.MemberInfo
Multiple overloads
System.Type.GetProperties() : System.Reflection.PropertyInfo []
System.Type.GetProperties(bindingAttr: System.Reflection.BindingFlags) : System.Reflection.PropertyInfo []
static member Array.join : delimiter:string -> xs:'a [] -> string
val lines : seq<obj []>

  type: seq<obj []>
  inherits: System.Collections.IEnumerable
val map : ('T -> 'U) -> seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
type FSharpValue =
  class
    static member GetExceptionFields : exn:obj * ?bindingFlags:System.Reflection.BindingFlags -> obj []
    static member GetRecordField : record:obj * info:System.Reflection.PropertyInfo -> obj
    static member GetRecordFields : record:obj * ?bindingFlags:System.Reflection.BindingFlags -> obj []
    static member GetTupleField : tuple:obj * index:int -> obj
    static member GetTupleFields : tuple:obj -> obj []
    static member GetUnionFields : value:obj * unionType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> UnionCaseInfo * obj []
    static member MakeFunction : functionType:System.Type * implementation:(obj -> obj) -> obj
    static member MakeRecord : recordType:System.Type * values:obj [] * ?bindingFlags:System.Reflection.BindingFlags -> obj
    static member MakeTuple : tupleElements:obj [] * tupleType:System.Type -> obj
    static member MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?bindingFlags:System.Reflection.BindingFlags -> obj
    static member PreComputeRecordConstructor : recordType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> (obj [] -> obj)
    static member PreComputeRecordConstructorInfo : recordType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> System.Reflection.ConstructorInfo
    static member PreComputeRecordFieldReader : info:System.Reflection.PropertyInfo -> (obj -> obj)
    static member PreComputeRecordReader : recordType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> (obj -> obj [])
    static member PreComputeTupleConstructor : tupleType:System.Type -> (obj [] -> obj)
    static member PreComputeTupleConstructorInfo : tupleType:System.Type -> System.Reflection.ConstructorInfo * System.Type option
    static member PreComputeTuplePropertyInfo : tupleType:System.Type * index:int -> System.Reflection.PropertyInfo * (System.Type * int) option
    static member PreComputeTupleReader : tupleType:System.Type -> (obj -> obj [])
    static member PreComputeUnionConstructor : unionCase:UnionCaseInfo * ?bindingFlags:System.Reflection.BindingFlags -> (obj [] -> obj)
    static member PreComputeUnionConstructorInfo : unionCase:UnionCaseInfo * ?bindingFlags:System.Reflection.BindingFlags -> System.Reflection.MethodInfo
    static member PreComputeUnionReader : unionCase:UnionCaseInfo * ?bindingFlags:System.Reflection.BindingFlags -> (obj -> obj [])
    static member PreComputeUnionTagMemberInfo : unionType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> System.Reflection.MemberInfo
    static member PreComputeUnionTagReader : unionType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> (obj -> int)
  end

Full name: Microsoft.FSharp.Reflection.FSharpValue
static member FSharpValue.GetRecordFields : record:obj * ?bindingFlags:System.Reflection.BindingFlags -> obj []
static member FSharpValue.GetTupleFields : tuple:obj -> obj []
val props : System.Reflection.PropertyInfo []

  type: System.Reflection.PropertyInfo []
  implements: System.ICloneable
  implements: System.Collections.IList
  implements: System.Collections.ICollection
  implements: System.Collections.IStructuralComparable
  implements: System.Collections.IStructuralEquatable
  implements: System.Collections.Generic.IList<System.Reflection.PropertyInfo>
  implements: System.Collections.Generic.ICollection<System.Reflection.PropertyInfo>
  implements: seq<System.Reflection.PropertyInfo>
  implements: System.Collections.IEnumerable
  inherits: System.Array
val line : 'a
val prop : System.Reflection.PropertyInfo

  type: System.Reflection.PropertyInfo
  implements: System.Reflection.ICustomAttributeProvider
  implements: System.Runtime.InteropServices._MemberInfo
  implements: System.Runtime.InteropServices._PropertyInfo
  inherits: System.Reflection.MemberInfo
Multiple overloads
System.Reflection.PropertyInfo.GetValue(obj: obj, index: obj []) : obj
System.Reflection.PropertyInfo.GetValue(obj: obj, invokeAttr: System.Reflection.BindingFlags, binder: System.Reflection.Binder, index: obj [], culture: System.Globalization.CultureInfo) : obj
type Test =
  class
    new : colA:string * colB:int -> Test
    member ColA : string
    member ColB : int
  end

Full name: Csv.Test
val colA : string

  type: string
  implements: System.IComparable
  implements: System.ICloneable
  implements: System.IConvertible
  implements: System.IComparable<string>
  implements: seq<char>
  implements: System.Collections.IEnumerable
  implements: System.IEquatable<string>
val colB : int

  type: int
  implements: System.IComparable
  implements: System.IFormattable
  implements: System.IConvertible
  implements: System.IComparable<int>
  implements: System.IEquatable<int>
  inherits: System.ValueType
Multiple items
val int : 'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------

type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>

  type: int<'Measure>
  implements: System.IComparable
  implements: System.IConvertible
  implements: System.IFormattable
  implements: System.IComparable<int<'Measure>>
  implements: System.IEquatable<int<'Measure>>
  inherits: System.ValueType


--------------------

type int = int32

Full name: Microsoft.FSharp.Core.int

  type: int
  implements: System.IComparable
  implements: System.IFormattable
  implements: System.IConvertible
  implements: System.IComparable<int>
  implements: System.IEquatable<int>
  inherits: System.ValueType
val x : Test
member Test.ColA : string

Full name: Csv.Test.ColA
member Test.ColB : int

Full name: Csv.Test.ColB
val testData : seq<Test>

Full name: Csv.testData

  type: seq<Test>
  inherits: System.Collections.IEnumerable
val i : int

  type: int
  implements: System.IComparable
  implements: System.IFormattable
  implements: System.IConvertible
  implements: System.IComparable<int>
  implements: System.IEquatable<int>
  inherits: System.ValueType
static member Seq.csv : separator:string -> headerMapping:(string -> string) -> data:seq<'a> -> seq<string>
val propertyName : string

  type: string
  implements: System.IComparable
  implements: System.ICloneable
  implements: System.IConvertible
  implements: System.IComparable<string>
  implements: seq<char>
  implements: System.Collections.IEnumerable
  implements: System.IEquatable<string>
static member Seq.write : path:string -> data:seq<'a> -> unit
val distinctBy : ('T -> 'Key) -> seq<'T> -> seq<'T> (requires equality)

Full name: Microsoft.FSharp.Collections.Seq.distinctBy
val testInstance : Test
property Test.ColA: string
val probe : Test
property Test.ColB: int
val columnName : string

  type: string
  implements: System.IComparable
  implements: System.ICloneable
  implements: System.IConvertible
  implements: System.IComparable<string>
  implements: seq<char>
  implements: System.Collections.IEnumerable
  implements: System.IEquatable<string>

More information

Link: http://fssnip.net/3U
Posted: 3 years ago
Author: Rainer Schuster (website)
Tags: CSV, serialize, writer