主流选 apache/parquet-go,它是 Apache 官方维护的 Go 实现,兼容 Parquet 2.0,支持完整 schema 演化和压缩;原 xitongxue 版已归档,不推荐新项目使用。

用 parquet-go 还是 apache/parquet-go?
现在主流选 apache/parquet-go,它是 Apache 官方维护的 Go 实现,兼容 Parquet 2.0 规范,支持更完整的 schema 演化和压缩选项。而老的 parquet-go(xitongxue 版)已归档,不支持 INT96 时间戳、不维护 Arrow 兼容性,新项目别踩这个坑。
- 安装命令必须用
go get github.com/apache/parquet-go@latest,别漏掉@latest,否则可能拉到半年前的旧 commit - 它不自带 Arrow 集成,如果要和
arrow-go互转数据,得自己桥接parquet-go的RowGroupReader和 Arrow 的array.Record - 对 Windows 路径分隔符敏感:写文件时若路径含
\,WriteFile会静默失败,建议统一用/或filepath.ToSlash()
WriteFile 写 Parquet 文件的最小可靠流程
不能只调 parquet.WriteFile 就完事——它内部不校验 schema 合法性,字段名含空格或重复会导致读取端解析崩溃,且默认不压缩,文件体积大三倍以上。
- schema 必须显式定义:用
parquet.NewSchema构建,字段名只允许字母、数字、下划线,开头不能是数字 - 压缩必须手动开:传入
parquet.CompressionCodec(1)(1 = SNAPPY),ZSTD 需要额外 build tag:go build -tags zstd - 写入前检查数据长度:每列切片长度必须一致,否则
WriteFile会 panic 报"mismatched column lengths" - 示例关键行:
parquet.WriteFile("data.parquet", records, parquet.CompressionCodec(1), parquet.SchemaOf(&MyStruct{}))
读 ReadFile 时字段映射错位的常见原因
读出来字段值全乱了,不是数据问题,基本是 schema 解析和结构体 tag 对不上。Parquet 不靠字段顺序匹配,而是靠列名(column name)和结构体字段的 parquet tag 严格对应。
- 结构体字段没加
parquet:"name"tag,默认用字段名小写,但 Parquet 文件里列名可能是user_id,而你的字段叫UserID,没 tag 就变成userid,匹配失败 - 嵌套 struct 支持弱:比如
Address struct { City string `parquet:"city"` },必须整个Address字段也带 tag,如Addr Address `parquet:"address"`,否则解析器找不到嵌套路径 - 读部分列更快:用
parquet.ReadColumn直接读单列,避免把整行反序列化进 struct,内存省一半以上 - 遇到
"unknown type: INT96"错误,说明文件含 legacy 时间戳,需加解码选项:parquet.WithTimePrecision(parquet.Microseconds)
并发读写 Parquet 文件的安全边界
parquet-go 的 reader/writer 实例都不是 goroutine-safe 的,但底层文件句柄可以复用——重点在“谁控制打开和关闭”。
立即学习“go语言免费学习笔记(深入)”;
- 多个 goroutine 同时
ReadFile没问题,因为每次调用都新建 reader;但共用一个*parquet.File实例并发调RowGroupReader会 panic - 写文件时不能并发往同一个
*os.File写,哪怕用不同 writer;正确做法是每个 goroutine 写独立文件,最后用 Parquet 的merge工具合并(或自己用parquet.MergeFiles) - 内存映射读(
parquet.OpenFile)比ReadFile快 2–3 倍,但要求文件不被其他进程修改,生产环境用前得加文件锁
*)都会导致静默错位,不是报错,是读出错误值——这点最容易被忽略。


















