Describe this repository
This commit is contained in:
1 parent
f87ec7522c
commit
b4654a48b0
1 file changed
+9
-209
@@ -1,213 +1,13 @@
|
|||||||
Go CSV
|
# Contributions to gocarina/gocsv
|
||||||
=====
|
|
||||||
|
|
||||||
The GoCSV package aims to provide easy serialization and deserialization functions to use CSV in Golang
|
The GoCSV package aims to provide easy CSV serialization and deserialization to the golang programming language
|
||||||
|
|
||||||
API and techniques inspired from https://godoc.org/gopkg.in/mgo.v2
|
This repository holds only my commits to the upstream project, with their original author, date and diff.
|
||||||
|
Each of my commits is preceded by a snapshot of the upstream files it touched, so every diff shows exactly what I changed.
|
||||||
|
|
||||||
[](https://godoc.org/github.com/gocarina/gocsv)
|
## Merged pull requests
|
||||||
[](https://travis-ci.org/gocarina/gocsv)
|
|
||||||
|
|
||||||
Installation
|
- [Add MarshalBytesWithoutHeaders](https://github.com/gocarina/gocsv/pull/305) (2026-10-12)
|
||||||
=====
|
- [Fix date layout in README and full example](https://github.com/gocarina/gocsv/pull/304) (2026-10-12)
|
||||||
|
- [Make SetHeaderNormalizer safe to call while decoding](https://github.com/gocarina/gocsv/pull/303) (2026-10-12)
|
||||||
```go get -u github.com/gocarina/gocsv```
|
- [Parse integer fields as base 10 (fixes #182)](https://github.com/gocarina/gocsv/pull/293) (2026-09-05)
|
||||||
|
|
||||||
Full example
|
|
||||||
=====
|
|
||||||
|
|
||||||
Consider the following CSV file
|
|
||||||
|
|
||||||
```csv
|
|
||||||
|
|
||||||
client_id,client_name,client_age
|
|
||||||
1,Jose,42
|
|
||||||
2,Daniel,26
|
|
||||||
3,Vincent,32
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Easy binding in Go!
|
|
||||||
---
|
|
||||||
|
|
||||||
```go
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Customizable Converters
|
|
||||||
---
|
|
||||||
|
|
||||||
```go
|
|
||||||
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Nested structs
|
|
||||||
---
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```go
|
|
||||||
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:
|
|
||||||
|
|
||||||
```go
|
|
||||||
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`.
|
|
||||||
|
|
||||||
Customizable CSV Reader / Writer
|
|
||||||
---
|
|
||||||
|
|
||||||
```go
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
Reference in new issue
Block a user