如何使用Golang读取CSV文件_Golang encoding/csv CSV解析示例

csv.NewReader必须传入io.Reader接口类型,如*os.File;不可直接传字符串路径。需先os.Open再defer Close,支持HTTP响应等各类io.Reader。ReadAll适合小文件,Read循环适合大文件和细粒度错误处理。

csv.NewReader 读取文件时必须传入 *os.File 或 io.Reader

直接传入文件路径字符串会编译失败,csv.NewReader 只接受实现了 io.Reader 接口的类型。常见错误是写成 csv.NewReader("data.csv"),这会报错 cannot use "data.csv" (type string) as type io.Reader

  • 正确做法:先用 os.Open 打开文件,得到 *os.File(它实现了 io.Reader
  • 别忘了用 defer f.Close(),否则文件句柄泄漏
  • 如果数据来自 HTTP 响应体、bytes.Buffer 或 strings.Reader,同样可直接传入 —— 它们都满足 io.Reader

ReadAll 和逐行 Read 的选择取决于内存与错误处理需求

ReadAll 会一次性把整个 CSV 加载进内存并返回 [][]string,适合小文件且不关心某一行出错时继续解析的场景;而用循环调用 Read 可以逐行处理、及时响应错误、控制内存占用。

  • ReadAll 遇到任何解析错误(如引号不匹配、字段数不一致)就直接返回错误,不提供出错行号
  • Read 循环时,每行返回 []string,错误只影响当前行,可通过 csv.ParseError 类型断言获取 LineField 位置
  • 大文件(>100MB)务必避免 ReadAll,否则可能 OOM

设置 Comma 和 TrimLeadingSpace 处理常见格式变体

默认分隔符是英文逗号 ,,但实际 CSV 可能用制表符、分号甚至中文顿号;另外 Excel 导出的 CSV 常在字段前带空格,不处理会导致字段值开头多出空格。

  • 修改分隔符:reader.Comma = '\t'(制表符)或 reader.Comma = ';'
  • 自动裁剪字段首尾空格:reader.TrimLeadingSpace = true(注意:只裁前导空格,不裁结尾)
  • 若需裁剪结尾空格,得手动对每行字段调用 strings.TrimSpace
  • 注意:这些设置必须在第一次调用 ReadReadAll 之前完成
package main

import (
	"encoding/csv"
	"fmt"
	"os"
	"strings"
)

func main() {
	f, err := os.Open("users.csv")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	reader := csv.NewReader(f)
	reader.Comma = ','           // 可省略,默认就是 ,
	reader.TrimLeadingSpace = true

	records, err := reader.ReadAll()
	if err != nil {
		if e, ok := err.(*csv.ParseError); ok {
			fmt.Printf("parse error at line %d, field %d: %v\n", e.Line, e.Field, e.Err)
		} else {
			panic(err)
		}
		return
	}

	for i, record := range records {
		if i == 0 {
			continue // skip header
		}
		name := strings.TrimSpace(record[0])
		email := strings.TrimSpace(record[1])
		fmt.Printf("User %d: %s <%s>\n", i, name, email)
	}
}
CSV 解析真正麻烦的不是读取本身,而是字段里嵌了换行符、双引号、逗号却没被正确转义 —— 这类问题不会在 OpenNewReader 阶段暴露,只会在 Read 时触发 csv.ParseError,而且错误信息里的 Line 是逻辑行号(含跨行字段),不是文件字节偏移,调试时容易误判。