Zarr格式存气象数据?读写速度快不快?
“Zarr格式存气象数据?读写速度快不快?”这个问题,通常出现在气象栅格数据越来越大、NetCDF 文件越来越多、Python 读取越来越慢的时候。对 GIS 用户来说,Zarr 不是一个“更酷的文件后缀”,而是一种更适合分块、并行、云端对象存储和时间序列气象数据分析的数据组织方式。
本文从 GIS 和气象数据处理的实际场景出发,说明 Zarr 格式适不适合存气象数据、读写速度为什么可能更快、什么时候反而不一定快,以及如何用 Python、xarray 和 Dask 做一个可复现的读写流程。
引言:Zarr格式存气象数据适合解决什么问题
气象数据通常有几个典型特点:时间维度长、空间网格规则、变量多、文件体积大。例如温度、降水、风速、气压等变量,往往按小时、日、月持续累积。如果仍然用大量单独的 NetCDF 文件管理,常见问题包括:
- 批量读取多个 NetCDF 文件时,文件打开和元数据解析耗时明显。
- 只想读取某个区域或某个时间段,却不得不扫描很多文件。
- 在 WebGIS、云服务器或对象存储上访问时,随机读取效率较差。
- 多人协作时,复制和移动大文件成本高。
- Python 分析中需要频繁重采样、裁剪、按时间聚合,I/O 成为瓶颈。
Zarr 格式的核心优势是把多维数组拆成许多小块,也就是 chunk。读取时可以只访问需要的块,而不是每次都处理整个大文件。对于气象网格数据,这个特性非常重要。

背景:气象数据为什么容易遇到读写瓶颈
在 GIS 工作流中,气象数据常见格式包括 NetCDF、GRIB、GeoTIFF、HDF 和 Zarr。它们都能存储栅格或多维数组,但适用场景不同。
以气象再分析数据为例,一个数据集可能包含如下维度:
- time:时间,例如逐小时、逐日或逐月。
- lat:纬度。
- lon:经度。
- level:高度层或气压层。
- variable:变量,例如气温、降水、风速、相对湿度。
如果只分析一个月的数据,传统文件方式问题不大。但如果要分析 10 年逐小时降水,或者在全国范围内做逐日气象指标统计,读取性能就会明显影响效率。
很多 GIS 用户遇到的慢,并不是计算公式慢,而是数据读取慢。尤其是以下操作:
- 循环打开上千个 NetCDF 文件。
- 每次只取一个小区域,却反复读取完整文件。
- 将多年的气象数据合并成一个大数组后内存不足。
- 在网络盘、对象存储或远程服务器上读取气象数据。
- 用 Python 脚本反复转换、裁剪、聚合。
这正是 Zarr 格式存气象数据受到关注的原因。
原理:Zarr格式读写速度快不快,取决于分块和访问方式
Zarr 格式不是简单地“天然更快”。它快不快,主要取决于三个因素:分块方式、压缩方式和读取模式。
Zarr 的分块存储是什么
Zarr 会把一个大的多维数组拆成多个小块。例如一个气象变量的维度是 time、lat、lon,可以按如下方式分块:
time: 24
lat: 256
lon: 256
这表示每个 chunk 存储 24 个时间步、256 行纬度、256 列经度的数据。读取某一天、某个区域时,只需要访问相关 chunk。
为什么 Zarr 适合气象数据
- 气象数据天然是多维数组,和 Zarr 的数据模型匹配。
- 时间序列很长时,Zarr 可以按时间块读取。
- 区域分析时,可以按空间块读取。
- 配合 Dask 可以并行计算,不必一次把全部数据读入内存。
- 适合对象存储,例如 S3、MinIO、云盘类数据湖场景。
Zarr 什么时候可能不快
Zarr 格式存气象数据并不意味着所有操作都会变快。下面几种情况可能并不理想:
- chunk 设置不合理,例如按时间读取却把 time chunk 设得过小。
- 文件数量极多且存储在普通机械硬盘上,元数据和小文件访问开销明显。
- 每次都全量读取整个数据集,Zarr 的优势不明显。
- 压缩算法选择过重,CPU 解压成为瓶颈。
- 网络延迟高,对象存储请求次数过多。
所以,“Zarr格式读写速度快不快”的答案应该是:在按时间、空间、变量进行选择性读取时,通常更适合大规模气象数据;但需要合理设置 chunk,不能只改格式不改数据组织方式。
步骤:用 xarray 将 NetCDF 气象数据转换为 Zarr
下面给出一个常见工作流:把一批 NetCDF 气象数据转换为 Zarr,然后按区域和时间读取。适合 Python GIS、气象数据分析和遥感栅格时序处理场景。
1. 安装必要 Python 包
建议使用 conda 环境管理依赖,避免 NetCDF、HDF5 和压缩库版本冲突。
conda create -n zarr_gis python=3.11 -y
conda activate zarr_gis
conda install -c conda-forge xarray dask netcdf4 h5netcdf zarr numcodecs pandas numpy -y
如果还需要处理矢量边界裁剪,可以再安装 geopandas、rioxarray 和 rasterio:
conda install -c conda-forge geopandas rioxarray rasterio -y
2. 读取多个 NetCDF 文件
假设目录中有逐月 NetCDF 文件:
data/
temp_2020_01.nc
temp_2020_02.nc
temp_2020_03.nc
可以使用 xarray 的 open_mfdataset 合并:
import xarray as xr
ds = xr.open_mfdataset(
"data/temp_2020_*.nc",
combine="by_coords",
chunks={"time": 24, "lat": 256, "lon": 256}
)
print(ds)
这里的 chunks 参数很重要。它不是普通参数,而是决定后续 Zarr 存储结构和 Dask 并行任务粒度的关键。
3. 检查维度和坐标名称
不同气象数据集可能使用 latitude、longitude,也可能使用 lat、lon。转换前建议先检查:
print(ds.dims)
print(ds.coords)
print(ds.data_vars)
如果坐标名称不统一,可以先重命名:
ds = ds.rename({
"latitude": "lat",
"longitude": "lon"
})
坐标统一后,后续裁剪、切片和 WebGIS 服务发布会更清晰。
4. 写出为 Zarr 格式
将数据写入本地 Zarr 目录:
ds.to_zarr(
"output/temperature_2020.zarr",
mode="w",
consolidated=True
)
参数 consolidated=True 会将元数据合并,通常有利于读取性能,尤其是远程访问 Zarr 数据时。
5. 重新读取 Zarr 数据
zds = xr.open_zarr(
"output/temperature_2020.zarr",
consolidated=True
)
print(zds)
如果需要按时间读取:
subset_time = zds.sel(time=slice("2020-06-01", "2020-06-30"))
如果需要按经纬度范围读取:
subset_area = zds.sel(
lon=slice(110, 120),
lat=slice(35, 25)
)
注意:有些数据纬度是从北到南递减,所以 lat 的 slice 顺序可能是 slice(35, 25),而不是 slice(25, 35)。这是气象数据处理中非常常见的坑。
6. 对区域和时间做统计
例如计算一个月内区域平均温度:
monthly_mean = zds["t2m"].sel(
time=slice("2020-06-01", "2020-06-30"),
lon=slice(110, 120),
lat=slice(35, 25)
).mean(dim=["time", "lat", "lon"])
result = monthly_mean.compute()
print(result.values)
compute() 会触发实际计算。在此之前,Dask 通常只是构建任务图,并不会立即把所有数据读入内存。
步骤:如何粗略判断 Zarr 读写速度是否值得使用
实际项目中,不建议只听“Zarr 很快”就全量迁移。更稳妥的做法是用自己的数据做一个小测试。
1. 记录 NetCDF 读取耗时
import time
import xarray as xr
t0 = time.time()
ds_nc = xr.open_mfdataset(
"data/temp_2020_*.nc",
combine="by_coords"
)
subset_nc = ds_nc["t2m"].sel(
time=slice("2020-06-01", "2020-06-30"),
lon=slice(110, 120),
lat=slice(35, 25)
).mean().compute()
print("NetCDF cost:", time.time() - t0)
2. 记录 Zarr 读取耗时
import time
import xarray as xr
t0 = time.time()
ds_zarr = xr.open_zarr(
"output/temperature_2020.zarr",
consolidated=True
)
subset_zarr = ds_zarr["t2m"].sel(
time=slice("2020-06-01", "2020-06-30"),
lon=slice(110, 120),
lat=slice(35, 25)
).mean().compute()
print("Zarr cost:", time.time() - t0)
这个测试不能代表所有场景,但能回答一个关键问题:你的数据、你的硬盘、你的网络环境、你的读取模式下,Zarr 格式读写速度是否真的有改善。
常见坑:Zarr格式存气象数据时最容易出错的地方
1. chunk 设置和分析方式不匹配
如果经常按时间序列读取某一个站点附近区域,可以让 time chunk 稍大一些;如果经常按某一天做全国空间分析,可以让空间 chunk 更适合整幅栅格扫描。
错误示例是完全不考虑使用方式,直接用默认 chunk。这样可能导致读取一个小区域时也触发大量无关 chunk。
2. 纬度方向导致空间切片为空
很多气象数据的纬度从 90 到 -90 递减。如果使用:
ds.sel(lat=slice(25, 35))
可能返回空数据。此时需要改成:
ds.sel(lat=slice(35, 25))
读取前可以先查看:
print(ds.lat.values[:5])
print(ds.lat.values[-5:])
3. 坐标系理解错误
大多数全球气象数据使用经纬度坐标,通常对应 EPSG:4326 或类似地理坐标系统。但并不是所有气象数据都已经带有完整 GIS 坐标参考信息。
如果后续要和行政区矢量叠加,必须确认:
- 经度范围是 0 到 360,还是 -180 到 180。
- 纬度方向是递增还是递减。
- 变量单位是否需要转换,例如 K 转摄氏度。
- 时间是否为 UTC,是否需要转本地时间。
4. 小文件过多影响对象存储性能
Zarr 会把数据拆成许多 chunk 文件。chunk 太小会产生大量对象或小文件,在对象存储上可能导致请求次数过多,在本地文件系统上也可能带来目录扫描开销。
因此,Zarr 不是 chunk 越小越好,而是要在读取粒度、压缩效率和文件数量之间平衡。
5. 压缩算法选择不当
压缩可以减少存储体积和磁盘读取量,但解压也需要 CPU。对于频繁读取的数据,如果压缩过重,可能出现磁盘不慢、CPU 解压慢的情况。
在气象数据中,可以根据数据类型和精度需求选择压缩策略。不要在没有验证的情况下,为所有变量套用同一套压缩参数。
方法比较:Zarr、NetCDF、GeoTIFF 存气象数据怎么选
| 格式 | 适合场景 | 优势 | 限制 |
|---|---|---|---|
| Zarr | 多维气象数据、时间序列分析、云端对象存储、并行计算 | 分块读取灵活,适合 xarray 和 Dask,适合大规模数组 | chunk 设计要求高,小文件或对象数量可能较多 |
| NetCDF | 传统气象、海洋、科研数据交换 | 生态成熟,元数据表达能力强,科研软件支持广 | 多文件批量读取和云端随机访问可能不够理想 |
| GeoTIFF | 单期栅格、制图、GIS 软件加载、遥感影像交换 | GIS 软件兼容性强,适合二维栅格 | 不适合表达复杂多维气象时间序列 |
| COG | 云端发布单期栅格、WebGIS 按需读取 | HTTP Range 读取友好,适合地图服务和在线浏览 | 多时间、多变量管理不如 Zarr 自然 |
如果你的目标是科研交换和长期归档,NetCDF 仍然很常用。如果目标是 Python 中做大规模气象时序分析,Zarr 更值得考虑。如果目标是把某一天的降水结果发布到 GIS 或 WebGIS,GeoTIFF 或 COG 可能更直接。
检查清单:决定是否使用 Zarr 存气象数据前先看这几项
- 数据是否是多维数组:如果有 time、lat、lon、level 等维度,Zarr 更有意义。
- 是否经常按子区域读取:如果经常只读部分区域,Zarr 分块优势明显。
- 是否经常按时间段读取:如果只分析某几天或某几个月,合理 time chunk 很关键。
- 是否需要并行计算:如果配合 Dask,Zarr 更适合大规模延迟计算。
- 是否运行在对象存储上:如果数据在 S3、MinIO 或云端,Zarr 比传统大文件更适合按需访问。
- chunk 是否经过测试:不要盲目使用默认 chunk,应根据分析模式调整。
- 元数据是否完整:变量单位、坐标、时间、缺失值和属性都要保留。
- 下游软件是否支持:如果主要用户只使用 ArcGIS Pro 或传统桌面 GIS,需要评估兼容性和转换流程。
FAQ:Zarr格式存气象数据常见问题
Zarr格式存气象数据一定比 NetCDF 快吗?
不一定。Zarr 的优势主要体现在分块读取、并行计算和云端访问。如果你每次都是本地全量读取一个小 NetCDF 文件,Zarr 不一定更快。真正要比较,应使用自己的数据和实际读取模式测试。
Zarr 适合存逐小时气象数据吗?
适合。逐小时气象数据通常时间维度很长,Zarr 可以按 time、lat、lon 分块,配合 xarray 和 Dask 进行按时间段读取、聚合和统计。但需要根据常用分析方式设置 chunk。
Zarr 可以直接在 QGIS 或 ArcGIS Pro 中打开吗?
桌面 GIS 对 Zarr 的直接支持不如 GeoTIFF、NetCDF 普遍。实际工作中,常见做法是用 Python 读取 Zarr 后,把某个时间片或统计结果导出为 GeoTIFF,再放入 QGIS 或 ArcGIS Pro 制图分析。
Zarr 和 COG 哪个更适合 WebGIS?
如果是单期二维栅格在线浏览,COG 更直接。如果是多变量、多时间、多层级气象数据分析,Zarr 更适合后端计算和数据湖管理。很多项目会用 Zarr 做分析存储,用 COG 或瓦片服务做前端发布。
Zarr 的 chunk 应该怎么设置?
没有固定答案。应根据主要访问模式设置。如果常按月分析区域平均值,可以让 time chunk 覆盖合理时间段,空间 chunk 保持中等大小。如果常做单日全国图,可以让空间读取更连续。建议先用小样本测试几组 chunk,再决定正式方案。
把 NetCDF 转成 Zarr 会丢失元数据吗?
通常 xarray 会保留大量维度、坐标和变量属性,但仍建议转换后检查 attrs、coords、变量单位、缺失值编码和时间解释。对于严肃气象分析,元数据检查和数值一致性验证必须做。
结论:Zarr格式存气象数据值得用,但关键是按场景设计
Zarr格式存气象数据的价值,不在于把 NetCDF 换成另一个格式,而在于把气象多维数组变成更适合分块读取、并行计算和云端访问的数据结构。
如果你的工作是长时间序列气象分析、区域统计、Python 批处理、Dask 并行计算或对象存储访问,Zarr 通常值得尝试。读写速度快不快,取决于 chunk、压缩、硬件、网络和实际查询方式。
对 GIS 用户来说,比较稳妥的路线是:原始数据保留 NetCDF 或 GRIB,分析中间层使用 Zarr,最终制图和发布结果输出 GeoTIFF、COG 或 WebGIS 服务。这样既能兼顾气象数据分析效率,也能保证 GIS 工作流的兼容性。