如何在Python中读取一个gzip压缩的netcdf文件?

10
我有一个可用的Python程序,使用netCDF4模块中的Dataset命令读取了许多大型netCDF文件。这里是相关部分的片段:
from netCDF4 import Dataset
import glob

infile_root = 'start_of_file_name_'

for infile in sorted(glob.iglob(infile_root + '*')):
   ncin = Dataset(infile,'r')
   ncin.close()

我希望修改代码以读取被压缩的netCDF文件。这些文件在创建后被压缩,而不是内部压缩(即文件为*.nc.gz)。如果我要读取被压缩的文本文件,则命令如下:

from netCDF4 import Dataset
import glob
import gzip

infile_root = 'start_of_file_name_'

for infile in sorted(glob.iglob(infile_root + '*.gz')):
   f = gzip.open(infile, 'rb')
   file_content = f.read()
   f.close()

在谷歌上搜索了大约半个小时并阅读了netCDF4文档后,我能想到的唯一一种处理netCDF文件的方法是:

from netCDF4 import Dataset
import glob
import os

infile_root = 'start_of_file_name_'

for infile in sorted(glob.iglob(infile_root + '*.gz')):
   os.system('gzip -d ' + infile)
   ncin = Dataset(infile[:-3],'r')
   ncin.close()
   os.system('gzip ' + infile[:-3]) 

是否可以使用Dataset命令直接读取gzip文件?或者不通过os调用gzip进行读取?


Dataset docs 没有关于 gz 文件的任何说明,因此我认为它不受支持。我相信有一种方法可以在 Python 中解压缩它们,而不需要进行 gzip 系统调用,但我不知道是什么。你为什么需要让 Dataset 处理它呢? - Spencer Hill
我不想分别调用解压缩和重新压缩文件。我也尽量避免使用系统调用。 - eclark
1
gzip.open 返回一个类似文件的对象,可用于只读访问文件 - 但似乎 netCDF4 不支持该功能。如果是我,我会使用 Python gzip 模块解压缩到临时文件并保留原始文件。如果这是经常需要完成的任务,您可以开始维护已解压缩文件的缓存。如果文件被修改,您仍然需要解压缩和重新压缩,所以无妨。 - tdelaney
1
@tdelaney - 谢谢。使用gzip模块解压缩到临时文件是一个很好的建议。 - eclark
3个回答

10
从内存中读取数据集是自 netCDF4-1.2.8 版本开始支持的(更新日志):
import netCDF4
import gzip

with gzip.open('test.nc.gz') as gz:
    with netCDF4.Dataset('dummy', mode='r', memory=gz.read()) as nc:
        print(nc.variables)

查看Dataset文档中关于memory参数的描述。
使用xarray的替代解决方案:
import xarray as xr

with gzip.open("test.nc.gz") as fp:
    ds = xr.open_dataset(fp)

这个很好用。我使用xarray来处理netcdf文件,但是我不知道如何使用xarray进行类似的操作。到目前为止,我必须为此工作流添加一个单一的转换:https://stackoverflow.com/questions/46433812/simple-conversion-of-netcdf4-dataset-to-xarray-dataset - undefined
我已经添加了一个使用xarray的示例。 - undefined
谢谢。这个例子真的很有用。 - undefined

5

由于NetCDF4-Python封装了C NetCDF4库,因此您无法使用gzip模块传递文件对象。唯一的选择是使用gzip将其提取到临时文件中,这正如@tdelaney建议的那样。

如果您能控制这些文件的创建,那么NetCDF第4版文件在内部支持zlib压缩,因此使用gzip是多余的。如果您需要反复处理这些文件,将文件从版本3转换为版本4也可能会很有价值。


4

既然我刚刚也遇到了同样的问题,这里有一个现成的解决方案:

import gzip
import os
import shutil
import tempfile

import netCDF4

def open_netcdf(fname):
    if fname.endswith(".gz"):
        infile = gzip.open(fname, 'rb')
        tmp = tempfile.NamedTemporaryFile(delete=False)
        shutil.copyfileobj(infile, tmp)
        infile.close()
        tmp.close()
        data = netCDF4.Dataset(tmp.name)
        os.unlink(tmp.name)
    else:
        data = netCDF4.Dataset(fname)
    return data

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接