如何在 python 中读取 gzip netcdf 文件?

Posted

技术标签:

【中文标题】如何在 python 中读取 gzip netcdf 文件?【英文标题】:How to read a gzip netcdf file in python? 【发布时间】:2015-02-03 23:57:53 【问题描述】:

我有一个工作 python 程序,它使用来自 netCDF4 模块的 Dataset 命令读取许多大型 netCDF 文件。这是相关部分的sn-p:

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()

我想修改它以读入 gzip 压缩的 netCDF 文件。文件本身在创建后被压缩;它们不是内部压缩的(即文件是 *.nc.gz)。如果我正在阅读 gzip 压缩的文本文件,命令将是:

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 文件的内容,所以我认为它不受支持。我确信有一种方法可以在没有gzip 系统调用的情况下从 Python 中压缩它们,但我不知道它会是什么。为什么需要Dataset来处理? 我不想单独调用解压缩然后重新压缩文件。我也最想避免系统调用。 gzip.open 返回一个类似文件的对象,可用于对文件进行只读访问 - 但看起来 netCDF4 不支持。如果是我,我会使用 python gzip 模块解压缩到一个临时文件并保留原始文件。如果它需要经常完成,您可以开始维护您已解压缩的缓存。如果文件被修改了,你无论如何都需要解压缩并重新压缩,这算什么。 @tdelaney - 谢谢。使用 gzip 模块解压缩到临时文件是一个很好的建议。 【参考方案1】:

从 netCDF4-1.2.8 (Changelog) 起支持从内存中读取数据集:

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 documentation中memory参数的说明

【讨论】:

【参考方案2】:

由于我只是要解决同样的问题,这里有一个现成的解决方案:

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

【讨论】:

【参考方案3】:

因为 NetCDF4-Python 包装了 C NetCDF4 库,所以就使用 gzip 模块传入类似文件的对象而言,您很不走运。正如@tdelaney 所建议的,唯一的选择是使用 gzip 解压到一个临时文件。

如果您碰巧对这些文件的创建有任何控制权,NetCDF 版本 4 文件在内部支持 zlib 压缩,因此使用 gzip 是多余的。如果您需要重复处理这些文件,也可能值得将文件从版本 3 转换为版本 4。

【讨论】:

以上是关于如何在 python 中读取 gzip netcdf 文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何读取在 http 响应中发送的 GZip 内容

如何实现,读取远程文件,用GZIP压缩后保存成文件

在 python Apache Beam 中打开一个 gzip 文件

如何从 gzip 读取 json 字符串

如何有效地读取非常大的 gzip 压缩日志文件的最后一行?

如何使用带有 gzip 压缩选项的 pandas read_csv 读取 tar.gz 文件?