在Golang开发中,处理CSV格式的文件是常见需求,无论是导入用户数据、导出报表还是解析第三方提供的表格数据,都可以借助标准库的encoding/csv包实现。该包提供了完整的CSV读写接口,支持自定义分隔符、处理带引号的字段等常见场景,能够满足大部分业务需求。

读取CSV文件
读取CSV文件的核心是使用csv.NewReader创建读取器,然后通过Read或ReadAll方法获取内容。下面是一个读取本地CSV文件的示例:
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
// 打开CSV文件
file, err := os.Open("test.csv")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
// 创建CSV读取器
reader := csv.NewReader(file)
// 设置分隔符,默认是逗号,可根据实际情况修改
// reader.Comma = 't' // 如果是制表符分隔的CSV文件,可开启这行
// 读取所有记录
records, err := reader.ReadAll()
if err != nil {
fmt.Println("读取CSV失败:", err)
return
}
// 遍历输出内容
for i, record := range records {
fmt.Printf("第%d行内容: %vn", i+1, record)
}
}
逐行读取CSV
如果CSV文件体积较大,使用ReadAll一次性加载所有内容会占用较多内存,此时可以逐行读取:
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
file, err := os.Open("large.csv")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
reader := csv.NewReader(file)
// 跳过表头,如果需要保留表头可删除这行
_, err = reader.Read()
if err != nil {
fmt.Println("读取表头失败:", err)
return
}
// 逐行读取
for {
record, err := reader.Read()
if err != nil {
// 读到文件末尾时err为io.EOF
if err.Error() == "EOF" {
break
}
fmt.Println("读取行失败:", err)
return
}
fmt.Printf("读取到行内容: %vn", record)
}
}
写入CSV文件
写入CSV文件需要使用csv.NewWriter创建写入器,然后通过Write或WriteAll方法写入数据,最后调用Flush确保数据写入文件。
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
// 创建或打开CSV文件
file, err := os.Create("output.csv")
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()
// 创建CSV写入器
writer := csv.NewWriter(file)
// 设置分隔符,默认是逗号
// writer.Comma = 't'
// 准备要写入的数据,第一行通常是表头
header := []string{"姓名", "年龄", "城市"}
data := [][]string{
{"张三", "25", "北京"},
{"李四", "30", "上海"},
{"王五", "28", "广州"},
}
// 写入表头
err = writer.Write(header)
if err != nil {
fmt.Println("写入表头失败:", err)
return
}
// 写入所有数据行
err = writer.WriteAll(data)
if err != nil {
fmt.Println("写入数据失败:", err)
return
}
// 刷新缓冲区,确保数据写入文件
writer.Flush()
if err := writer.Error(); err != nil {
fmt.Println("刷新缓冲区失败:", err)
return
}
fmt.Println("CSV文件写入完成")
}
逐行写入CSV
如果需要动态生成数据逐行写入,可以使用Write方法:
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
file, err := os.Create("dynamic.csv")
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// 写入表头
err = writer.Write([]string{"ID", "商品名", "价格"})
if err != nil {
fmt.Println("写入表头失败:", err)
return
}
// 模拟动态生成数据并逐行写入
products := []struct {
ID int
Name string
Price float64
}{
{1, "鼠标", 99.9},
{2, "键盘", 199.5},
{3, "显示器", 899.0},
}
for _, p := range products {
row := []string{
fmt.Sprintf("%d", p.ID),
p.Name,
fmt.Sprintf("%.2f", p.Price),
}
err := writer.Write(row)
if err != nil {
fmt.Println("写入行失败:", err)
return
}
}
fmt.Println("逐行写入CSV完成")
}
解析复杂表格数据的注意事项
实际场景中的CSV文件可能存在各种特殊情况,处理时需要注意以下几点:
- 字段中包含分隔符:如果字段内容本身包含逗号,CSV文件通常会用双引号包裹该字段,encoding/csv包会自动处理这种情况,无需额外操作。
- 字段中包含换行符:合法的CSV文件中,包含换行符的字段也会被双引号包裹,读取器会自动识别,不会出现行解析错误。
- 自定义分隔符:如果CSV文件不是用逗号分隔,比如用制表符、分号等,可以通过设置
reader.Comma和writer.Comma修改分隔符。 - 处理空行:默认情况下,读取器会把空行解析为长度为0的记录,如果需要跳过空行,可以在读取后判断记录长度。
下面是一个处理带引号字段的CSV读取示例,假设test.csv内容如下:
姓名,简介 张三,"热爱编程,喜欢Golang" 李四,"毕业于清华大学,现居上海"
package main
import (
"encoding/csv"
"fmt"
"os"
)
func main() {
file, err := os.Open("test.csv")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
fmt.Println("读取失败:", err)
return
}
for _, record := range records {
fmt.Printf("姓名: %s, 简介: %sn", record[0], record[1])
}
}
运行后会正确输出带逗号的简介内容,不会被错误分割。
Golangencoding/csvCSV读写表格数据解析修改时间:2026-06-16 12:00:32