Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
134: encoding/csv
Think of a CSV file like a very strict, old-school filing system. Imagine you have a physical ledger where every page is a row, and every entry is separated by a vertical line. If you wanted to move that data into a modern database, you wouldn't just read the page as one long string of text; you'd use a template to slice the page into specific columns so you know exactly which piece of text is the "Customer Name" and which is the "Order Total."
In Go, the encoding/csv package is that template. While it's tempting to just use strings.Split(line, ","), I'm telling you right now: don't do it. Real-world CSVs are messy. They have quoted strings that contain commas inside them (like "New York, NY"), and strings.Split will tear that right in half, ruining your data. The csv package handles those edge cases for you.
Turning a Text File into Slices
When you're reading a CSV, you're essentially turning a stream of bytes into a series of string slices ([]string). Each slice represents one row. Here is how I usually set this up when I'm parsing a list of server assets:
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
file, err := os.Open("servers.csv")
if err != nil {
panic(err)
}
defer file.Close()
reader := csv.NewReader(file)
// ReadAll is great for small files, but for huge ones,
// you'd want to use reader.Read() in a loop.
records, err := reader.ReadAll()
if err != nil {
panic(err)
}
for _, row := range records {
fmt.Printf("Hostname: %s, IP: %s\n", row[0], row[1])
}
}
Notice how ReadAll() gives us a [][]string. It's a slice of slices. If your file is massive—say, a 2GB export from a database—ReadAll() will eat all your RAM. In those cases, I use a for loop with reader.Read() to process the file one line at a time.
Dumping Data Back to Disk
Writing is the mirror image of reading. You provide the csv.Writer with a slice of strings, and it handles the quoting and comma-placement for you. I've seen plenty of devs forget the most important part of the writing process: the flush.
func writeInventory(filename string, data [][]string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
writer := csv.NewWriter(file)
// WriteAll handles the looping and the flushing for you.
// If you use writer.Write() manually, you MUST call writer.Flush().
if err := writer.WriteAll(data); err != nil {
return err
}
return nil
}
The Flush Trap
If you aren't using WriteAll and you're instead calling writer.Write(row) inside a loop, the data isn't written to the file immediately. It's stored in a buffer to make the process faster. If your program exits or the function returns before you call writer.Flush(), you'll end up with a truncated or completely empty file. It's a classic "where did my data go?" bug that usually takes ten minutes of staring at the code to find.
One last tip: if you encounter a file that uses semicolons (;) instead of commas—which happens a lot with European Excel exports—you don't need a different package. Just set reader.Comma = ';' after initializing your reader.
📋 Practical Task
Build a Product Price Inflator
You have been given a CSV file named products.csv with the following content:
ProductName,Price
Laptop,1200.00
Mouse,25.50
Keyboard,75.00
Monitor,300.00
Write a Go program that does the following:
- Reads
products.csv. - Skips the header row.
- Parses the price (the second column) as a float.
- Increases the price by 10%.
- Writes the updated data (including the header) to a new file called
updated_products.csv.
Make sure you handle the string-to-float conversion using strconv.ParseFloat and format the new price back to two decimal places using fmt.Sprintf.
There are no comments for now.