Search code examples
.netvisual-studio-2010csvf#filehelpers

F# CSV FileHelpers


Im following the steps described below to read csv but get runtime error at the last line.
(TypeInitializationException)
Can anyone tell me what's wrong here?

http://www.markstaples.com/2009/01/08/parsing-csv-files-in-f/

module ReadCsv //-------------------------------------  
open System  
open FileHelpers  
[<DelimitedRecord(",")>]  
[<IgnoreFirst(1)>]  
type CsvRecord =  
    class  
       val field1 : string  
    end

type oneRow() =  
    class  
        [<DefaultValue>]  
        val mutable Str1: string  
        [<DefaultValue>]  
       val mutable Str2: string  
   end

let engine = new FileHelperEngine(typeof<CsvRecord>)  
let res = engine.ReadFile("C:/Users/Admin/Desktop/test.csv")  

module main //--------------------------------  
let downcast_Customer_Array = Array.map (fun (a:obj) -> a :?> ReadCsv.CsvRecord)  
let res_Customers = downcast_Customer_Array ReadCsv.res  

Solution

  • John's comment is on track, you're probably trying to read a file that doesn't exist. In Windows, backslash is used for path separation, not (forward) slash. These backslashes need to be escaped in an F# string literal. The reason why you're seeing this as TypeInitializationException is that this code is executed when the type is loaded. Had it been in a function, it would execute when called instead, and you would get the expected exception.

    There are several ways of escaping the backslashes, pick one:

    let res = engine.ReadFile("C:\\Users\\Admin\\Desktop\\test.csv")
    let res = engine.ReadFile(@"C:\Users\Admin\Desktop\test.csv")
    let res = engine.ReadFile("""C:\Users\Admin\Desktop\test.csv""")
    

    That last one, triple-quoting, is part of F# 3.0. http://blogs.msdn.com/b/fsharpteam/archive/2012/07/19/more-about-fsharp-3.0-language-features.aspx

    Edit Your real error is obscured by the fact that your code runs in type initialization. Try structuring your code differently:

    module ReadCsv = //-------------------------------------  
       open System  
       open FileHelpers  
    
       [<DelimitedRecord(",")>]  
       [<IgnoreFirst(1)>]  
       type CsvRecord =  
           class  
              val field1 : string  
           end
    
       let read file = 
          let engine = new FileHelperEngine(typeof<CsvRecord>)  
          engine.ReadFile(file) 
          |> Array.map (fun row -> row :?> CsvRecord)
    
    module Main = //--------------------------------  
        [<EntryPoint>]
        let main argv = 
           let results = ReadCsv.read "C:/Users/Admin/Desktop/test.csv"
           printfn "%A" results
           0 // return an integer exit code
    

    Now, instead of TypeInitializationException we get a BadUsageException with the message "The record class CsvRecord need a constructor with no args (public or private)". Much more useful! Fixing that, the code works as expected:

    module ReadCsv = //-------------------------------------  
       open System  
       open FileHelpers  
    
       [<DelimitedRecord(",")>]  
       [<IgnoreFirst(1)>]  
       type CsvRecord() =  
           class  
              [<DefaultValue>]
              val mutable field1 : string  
           end
    
       let read file = 
          let engine = new FileHelperEngine(typeof<CsvRecord>)  
          engine.ReadFile(file) 
          |> Array.map (fun row -> row :?> CsvRecord)
    
    module Main = //--------------------------------  
        [<EntryPoint>]
        let main argv = 
           let results = ReadCsv.read "C:/Users/Admin/Desktop/test.csv"
           results |> Seq.iter (fun r -> printfn "%s" r.field1)
           0 // return an integer exit code