Bettercsv is an alternative to the native Go csv. It provides several additional features:
- A method for retrieving the headers.
- Allows reading to maps with the headers as keys and the fields as values.
- Allows gracefully handling errors to continue reading on error.
// New Attributes:
SkipLineOnErr bool // Skips line when error occurs, allowing reader to continue
// New Methods:
func (r *Reader) Headers() (headers []string, err error)
func (r *Reader) ReadToMap() (recordMap map[string]string, err error)
func (r *Reader) ReadAllToMaps() (records []map[string]string, err error)
func (r *Reader) ReadAllWithErrors() (records [][]string, errs []error)
func (r *Reader) ReadAllToMapsWithErrors() (records []map[string]string, errs []error)
text.csv
first,last,email
John,Doe,[email protected]
Jane,Doe,[email protected]
Initialize our reader:
csvfile, err := os.Open("text.csv")
reader := bettercsv.NewReader(csvfile)
Calling reader.Headers()
will return [first last email]
. Note: Calling .Headers()
will advance the reader to the second line.
Calling reader.ReadToMap()
(after calling .Headers()
) will return:
[first:John last:Doe email:[email protected]]
You can call reader.ReadAllToMaps()
to return a slice of map[string]string
.
When reading line by line using reader.Read()
, if an error occurs, csv
will continue reading from the error and you will receive a cascade of errors. For example:
text.csv
first,last,email
John,Doe,[email protected]
Jane,Doe",[email protected]
June,Doe,[email protected]
Jeff,D"oe",[email protected]
Jim,Doe,jim,doe.com
Joan,Doe,[email protected]
Jack,"Do"e",[email protected]
Jill,Doe,[email protected]
test.go
...
for {
record, err := reader.Read()
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err)
}
fmt.Println(record)
}
...
Looping over this with reader.Read()
and printing each line will result in:
[first last email]
[John Doe [email protected]]
line 3, column 8: bare " in non-quoted-field
[]
line 4, column 0: wrong number of fields in line
[ [email protected]]
[June Doe [email protected]]
line 6, column 6: bare " in non-quoted-field
[]
line 7, column 2: bare " in non-quoted-field
[]
line 8, column 0: wrong number of fields in line
[ [email protected]]
line 9, column 0: wrong number of fields in line
[Jim Doe jim doe.com]
[Joan Doe [email protected]]
line 11, column 8: extraneous " in field
[]
line 14, column 0: extraneous " in field
[]
With reader.SkipLineOnErr = true
.
[first last email]
[John Doe [email protected]]
line 3, column 22: bare " in non-quoted-field
[]
[June Doe [email protected]]
line 5, column 23: bare " in non-quoted-field
[]
line 6, column 0: wrong number of fields in line
[Jim Doe jim doe.com]
[Joan Doe [email protected]]
line 8, column 23: extraneous " in field
[]
[Jill Doe [email protected]]
Notice the line numbers for bettercsv point to their correct lines and Jill Doe was removed completely from the standard csv library.
If you prefer to use the reader.ReadAll()
method but still want to skip errors, you can use reader.ReadAllWithErrors()
to receive both a slice of slices of records and a slice of all the errors.
values:
[[John Doe [email protected]]
[June Doe [email protected]]
[Joan Doe [email protected]]
[Jill Doe [email protected]]]
errors:
[line 3, column 22: bare \" in non-quoted-field
line 5, column 23: bare " in non-quoted-field
line 6, column 0: wrong number of fields in line
line 8, column 23: extraneous " in field]
You can also combine errors and maps with reader.ReadAllToMapsWithErrors()
.