github.com/xitongsys/parquet-go 是当前生产可用、维护活跃的唯一支持写入的 go 原生 parquet 库,需正确使用 parquet: tag、值类型传参、w.close() 及 writerconfig 配置压缩与行组大小。

用 github.com/xitongsys/parquet-go 写入 Parquet 文件最直接
Go 原生不支持 Parquet,目前生产可用、维护活跃的库只有 github.com/xitongsys/parquet-go(注意不是 parquet-go 的其他 fork 或旧版)。它支持结构体反射写入、自定义 schema、压缩(SNAPPY / GZIP)、嵌套字段,且不依赖 CGO。
常见错误是直接 import github.com/segmentio/parquet-go —— 这个库只读不写,调用 parquet.NewWriter 会 panic,报错信息类似:panic: write not supported。
实操建议:
- go get -u github.com/xitongsys/parquet-go
- 确保 struct 字段有
parquet:tag,否则字段被忽略(哪怕导出) - 顶层 struct 必须是值类型传入
Write,不能传指针(否则写入空值) - 写完必须调用
w.Close(),否则文件损坏或无数据
struct tag 怎么写才生效
Parquet-go 依赖 tag 显式声明类型和可空性,不靠 Go 类型自动推断。比如 int64 默认映射为 INT64,但若字段可能为 nil,就必须加 optional;字符串默认是 BYTE_ARRAY,但若想存为 UTF8 语义,得显式写 utf8。
典型正确写法:
type User struct {
ID int64 `parquet:"name=id, type=INT64"`
Name string `parquet:"name=name, type=BYTE_ARRAY, encoding=UTF8"`
Age *int32 `parquet:"name=age, type=INT32, optional"`
Tags []string `parquet:"name=tags, type=BYTE_ARRAY, encoding=UTF8, repeated"`
}
容易踩的坑:
-
type=值必须大写且严格匹配(如INT32不是int32) - 切片字段必须带
repeated,否则写入失败或静默丢弃 -
optional字段对应 Go 中的指针或 interface{},普通值类型即使设为 optional 也会被当成 required - 没有
parquet:tag 的字段完全不会写入,哪怕 struct 是导出的
写入时如何控制压缩和行组大小
Parquet 文件由多个行组(Row Group)组成,默认大小 128MB,但 Go 写入时实际按记录数或内存阈值 flush,需手动配置。压缩直接影响文件体积和后续查询性能,SNAPPY 是最常用平衡选择。
关键参数通过 parquet.NewWriter 的 parquet.WriterConfig 设置:
-
RowGroupSize:单位是记录数(非字节数),设为 10000 是较稳妥起点 -
CompressionType:可选parquet.CompressionCodec_SNAPPY、GZIP、UNCOMPRESSED -
PageSize:影响列内页大小,一般不用动(默认 8KB) - 注意:压缩类型必须在 Writer 创建时指定,不能写入中途切换
示例片段:
cfg := parquet.WriterConfig{
RowGroupSize: 10000,
CompressionType: parquet.CompressionCodec_SNAPPY,
}
w := parquet.NewWriter(f, schema, &cfg)
写入后文件打不开?检查这三点
生成的 .parquet 文件在 Spark / DuckDB / pyarrow 中打不开,大概率不是编码问题,而是元数据没写全或类型不兼容。
优先排查:
- 是否漏掉
w.Close()—— 这会导致 footer 缺失,所有读取器报Invalid Parquet file: missing magic bytes - schema 中是否有 unsupported 类型?例如
time.Time需转成int64+ 自定义逻辑,库不自动处理 - 嵌套结构(如 struct 字段)必须用
group类型 tag,例如parquet:"name=addr, type=GROUP",否则写入会 panic
真正麻烦的是跨语言兼容:Go 写的文件在 PyArrow 里读出来时间字段全是 null,往往是因为用了 INT96(已废弃),而现代工具只认 INT64 + logicalType TIMESTAMP_MILLIS —— 这需要自己构造 schema 并禁用 INT96,不是开箱即用的功能。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











