📊 Go – Read CSV Files with encoding/csv
: Syntax, Parsing & Examples (2025 Guide)
🧲 Introduction – Why Read CSV Files in Go?
CSV (Comma-Separated Values) files are widely used to store tabular data in a simple, portable format. In Go, the encoding/csv
package provides a clean and efficient way to read and parse CSV files for use in data processing, ETL pipelines, report generation, and backend APIs.
🎯 In this guide, you’ll learn:
- How to read and parse CSV files using Go
- Handle headers and row iteration
- Convert CSV rows into structs
- Best practices for validation and error handling
✅ Basic Example – Read CSV File Line by Line
package main
import (
"encoding/csv"
"fmt"
"log"
"os"
)
func main() {
file, err := os.Open("data.csv")
if err != nil {
log.Fatal(err)
}
defer file.Close()
reader := csv.NewReader(file)
for {
record, err := reader.Read()
if err != nil {
break
}
fmt.Println(record)
}
}
📤 Sample Output (for data.csv
):
["John" "30" "Engineer"]
["Alice" "25" "Designer"]
✅ Each record is a slice of strings, representing one row of data.
🧾 Read All CSV Rows at Once
records, err := reader.ReadAll()
if err != nil {
log.Fatal(err)
}
for _, row := range records {
fmt.Println(row)
}
✅ ReadAll()
loads the entire file. Use it only for small/medium-sized files.
🏷️ CSV With Headers – Skip the First Row
reader := csv.NewReader(file)
reader.FieldsPerRecord = -1 // Optional: Allow variable columns
// Read the first row as headers
headers, err := reader.Read()
if err != nil {
log.Fatal(err)
}
fmt.Println("Headers:", headers)
for {
record, err := reader.Read()
if err != nil {
break
}
fmt.Println(record)
}
✅ This skips the header row and processes the actual data.
📦 Mapping CSV Rows to Structs
type Person struct {
Name string
Age string
Job string
}
func main() {
file, _ := os.Open("data.csv")
defer file.Close()
reader := csv.NewReader(file)
reader.Read() // skip header
var people []Person
for {
record, err := reader.Read()
if err != nil {
break
}
p := Person{
Name: record[0],
Age: record[1],
Job: record[2],
}
people = append(people, p)
}
fmt.Println(people)
}
✅ A basic way to map each row to a struct manually.
🛠️ Real-World Use Case – Filtering CSV by Column
for {
record, err := reader.Read()
if err != nil {
break
}
if record[2] == "Engineer" {
fmt.Println("Engineer:", record[0])
}
}
✅ Filter data on-the-fly without loading the entire file.
📛 Handle Errors & EOF Gracefully
for {
record, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Println(record)
}
✅ Always check for io.EOF
to stop reading gracefully.
🧠 Best Practices
Practice | Why It Matters |
---|---|
✅ Use defer file.Close() | Properly releases resources |
✅ Use reader.Read() for control | More flexible than ReadAll() |
❌ Avoid ReadAll() on huge files | May cause memory exhaustion |
✅ Validate data column length | Prevents index out of range errors |
✅ Define constants for column indexes | Improves readability and maintainability |
📌 Summary – Recap & Next Steps
Go’s encoding/csv
package offers a powerful and clean way to parse CSV files. You can handle headers, read line-by-line or all at once, and map rows to structs for easier data handling.
🔍 Key Takeaways:
- Use
csv.NewReader(file)
andreader.Read()
to parse rows - Handle headers manually by skipping or storing them
- Validate and map data using struct fields
- Avoid
ReadAll()
for large CSV files
⚙️ Next: Explore Writing CSV Files, CSV Field Validation, or Building a CSV-to-JSON Converter in Go.
❓ FAQs – Go Read CSV Files
❓ How do I read a CSV file with headers?
✅ Use reader.Read()
to read and optionally skip the header row.
❓ What does ReadAll()
do?
✅ It reads all remaining records into memory—good for small files.
❓ How can I convert CSV rows to structs?
✅ Manually assign each field in a loop, or use a CSV-to-struct helper package.
❓ Can I use tabs instead of commas in CSV?
✅ Use reader.Comma = '\t'
to change the delimiter (e.g., for TSV files).
❓ Is encoding/csv
safe for concurrent use?
❌ No. It’s not safe for concurrent reads. Protect it with locks if needed.
Share Now :