Package [encoding/csv](<https://golang.org/pkg/encoding/csv/>) in standard library provides functionality for reading and writing CSV files.

Reading records from CSV file

Let’s read stock quotes from a CSV file:

date,open,high,low,close,volume,Name
2013-02-08,15.07,15.12,14.63,14.75,8407500,AAL
2013-02-11,14.89,15.01,14.26,14.46,8882000,AAL
2013-02-12,14.45,14.51,14.1,14.27,8126000,AAL
2013-02-13,14.3,14.94,14.25,14.66,10259500,AAL

https://codeeval.dev/gist/b1fb4a2a2f6c6d2e317f540928d890e8

As per Go best practices, CSV reader operates on io.Reader interface, which allows it to work on files, network connections, bytes in memory etc.

Read() method reads one CSV line at a time and returns []string slice with all fields in that line and an error.

Returning io.EOF as an error signifies successfully reaching end of file.

Reading all records from CSV file

Instead of calling Read() in a loop, we could read all records in one call:

r := csv.NewReader(f)
records, err := r.ReadAll()
if err != nil {
    log.Fatalf("r.ReadAll() failed with '%s'\\n", err)
}
// records is [][]string
fmt.Printf("Read %d records\\n", len(records))

This time we don’t have to special-case io.EOF as ReadAll does that for us.

Reading all records at once is simpler but will use more memory, especially for large CSV files.

Writing records to CSV file

Let’s now write simplified stock quotes to a CSV file:

https://codeeval.dev/gist/b6c47e08082b00a135b575fba1726ad8

Error handling here is not trivial.

We need to remember to Flush() at the end of writing, check if Flush() failed with Error() and also check that Close() didn’t fail.

The need to check Close() errors is why we didn’t use a simpler defer f.Close(). Correctness and robustness sometimes require more code.

Nalues that had , in them were quoted because comman is used as field separator.