The GoCSV package aims to provide easy serialization and deserialization functions to use CSV in Golang
API and techniques inspired from https://godoc.org/gopkg.in/mgo.v2
go get -u github.com/gocarina/gocsv
Consider the following CSV file
client_id,client_name,client_age
1,Jose,42
2,Daniel,26
3,Vincent,32
package main
import (
"fmt"
"os"
"github.com/gocarina/gocsv"
)
type NotUsed struct {
Name string
}
type Client struct { // Our example struct, you can use "-" to ignore a field
Id string `csv:"client_id"`
Name string `csv:"client_name"`
Age string `csv:"client_age"`
NotUsedString string `csv:"-"`
NotUsedStruct NotUsed `csv:"-"`
}
func main() {
clientsFile, err := os.OpenFile("clients.csv", os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
panic(err)
}
defer clientsFile.Close()
clients := []*Client{}
if err := gocsv.UnmarshalFile(clientsFile, &clients); err != nil { // Load clients from file
panic(err)
}
for _, client := range clients {
fmt.Println("Hello", client.Name)
}
if _, err := clientsFile.Seek(0, 0); err != nil { // Go to the start of the file
panic(err)
}
clients = append(clients, &Client{Id: "12", Name: "John", Age: "21"}) // Add clients
clients = append(clients, &Client{Id: "13", Name: "Fred"})
clients = append(clients, &Client{Id: "14", Name: "James", Age: "32"})
clients = append(clients, &Client{Id: "15", Name: "Danny"})
csvContent, err := gocsv.MarshalString(&clients) // Get all clients as CSV string
//err = gocsv.MarshalFile(&clients, clientsFile) // Use this to save the CSV back to the file
if err != nil {
panic(err)
}
fmt.Println(csvContent) // Display all clients as CSV string
}type DateTime struct {
time.Time
}
// Convert the internal date as CSV string
func (date *DateTime) MarshalCSV() (string, error) {
return date.Time.Format("20060102"), nil
}
// You could also use the standard Stringer interface
func (date *DateTime) String() (string) {
return date.String() // Redundant, just for example
}
// Convert the CSV string as internal date
func (date *DateTime) UnmarshalCSV(csv string) (err error) {
date.Time, err = time.Parse("20060102", csv)
return err
}
type Client struct { // Our example struct with a custom type (DateTime)
Id string `csv:"id"`
Name string `csv:"name"`
Employed DateTime `csv:"employed"`
}When decoding nested pointer structs, GoCSV allocates the pointers needed to
reach each field. An omitempty field still omits an empty leaf pointer value;
it does not prevent allocation of the enclosing structs.
By default, the fields of nested structs are prefixed with the parent field's name. For example:
type Foo struct {
B Bar
X int `csv:"x"`
}
type Bar struct {
A int `csv:"a"`
B int `csv:"b"`
}produces columns B.a, B.b, x.
Use the csv:"." tag to inline the nested struct's fields without that prefix; for example:
type Foo struct {
B Bar `csv:"."`
X int `csv:"x"`
}
type Bar struct {
A int `csv:"a"`
B int `csv:"b"`
}produces columns a, b, x.
Use a custom Decoder with UnmarshalDecoder to normalize values before they
are converted to struct fields. Parse the CSV first, keep its header row, and
map only the data columns that need cleaning. For example, the
runnable sanitizing example maps N/A to NaN
only in the Height column; quoted names, Unicode, other columns and ordinary
conversion errors keep their usual behavior.
The example uses csv.Reader.ReadAll, so it holds all records in memory. For
row-by-row processing, implement a SimpleDecoder whose GetCSVRow maps each
data row, then use UnmarshalDecoderToChan or UnmarshalDecoderToCallback. Neither
approach requires changing the process-wide SetCSVReader configuration.
func main() {
...
gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
r := csv.NewReader(in)
r.Comma = '|'
return r // Allows use pipe as delimiter
})
...
gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
r := csv.NewReader(in)
r.LazyQuotes = true
r.Comma = '.'
return r // Allows use dot as delimiter and use quotes in CSV
})
...
gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
//return csv.NewReader(in)
return gocsv.LazyCSVReader(in) // Allows use of quotes in CSV
})
...
gocsv.UnmarshalFile(file, &clients)
...
gocsv.SetCSVWriter(func(out io.Writer) *gocsv.SafeCSVWriter {
writer := csv.NewWriter(out)
writer.Comma = '|'
return gocsv.NewSafeCSVWriter(writer)
})
...
gocsv.MarshalFile(&clients, file)
...
}