使用with语句关闭GDAL数据集

时间:2018-04-04 10:09:21

标签: python gdal with-statement

考虑使用Jeff Knupp's blog中的with语句的基本示例:

class File():

    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        self.open_file = open(self.filename, self.mode)
        return self.open_file

    def __exit__(self, *args):
        self.open_file.close()

我有testfile,其中包含两行,' ABC'和' DEF'。一切都按预期工作:

with File('/tmp/testfile','r') as f:
    txt = [x.strip() for x in f.readlines()]
    print(txt)

# ['ABC', 'DEF']

with块之外调用类方法会给出预期的错误:

f.readlines()
  

ValueError Traceback(最近一次调用最后一次)    in()   ----> 1 f.readlines()

     

ValueError:关闭文件的I / O操作。

现在问我的问题:

如何使用gdal对象而不是文件来实现相同的行为?

我有一个类方法,它应该从磁盘读取数据并将其放入gdal栅格中进行进一步处理。完成后,我想适当地关闭生成的gdal栅格。通常,这可以通过将其设置为None并使用gdal.Unlink来完成。

但是,当我将所有内容放入上一个示例中的上下文结构时,我仍然可以与with块之外的数据集进行交互。

这是一个可重复的例子:

class Raster:
    '''Raster class with sidelength s'''
    def __init__(self,s):
        self.sidelength = s

    def __enter__(self):
        # create raster in memory
        driver = gdal.GetDriverByName('GTiff')
        self.raster = driver.Create('/vsimem/inmem.tif', self.sidelength, self.sidelength, 1, gdal.GDT_Float32)
        self.raster.GetRasterBand(1).WriteArray(np.random.rand(self.sidelength,self.sidelength))
        return self.raster

    def __exit__(self, *args):
        # close file and unlink
        self.raster = None
        gdal.Unlink('/vsimem/inmem.tif')

with块按预期工作:

with Raster(5) as r:
    print(r)

# <osgeo.gdal.Dataset; proxy of <Swig Object of type 'GDALDatasetShadow *' at 0x7f8078862ae0> >

但是在阻止之后,对象仍然存在,我仍然可以读取值:

print(r)

#<osgeo.gdal.Dataset; proxy of <Swig Object of type 'GDALDatasetShadow *' at 0x7f8078044a20> >

print(r.ReadAsArray())

#[[0.2549882  0.80292517 0.23358545 0.6284887  0.7294142 ]
# [0.9310723  0.21535267 0.9054575  0.60967094 0.9937953 ]
# [0.69144976 0.01727938 0.16800325 0.61249655 0.1785022 ]
# [0.16179436 0.43245795 0.7042811  0.4809799  0.85534436]
# [0.67751276 0.7560658  0.9594516  0.6294476  0.3539126 ]]

2 个答案:

答案 0 :(得分:3)

在保持对它的引用时,您无法真正关闭gdal数据集。您可以保留对Raster实例的引用,并使用r.raster访问with块中的数据集。

class Raster:
    '''Raster class with sidelength s'''
    def __init__(self,s):
        self.sidelength = s

    def __enter__(self):
        # create raster in memory
        driver = gdal.GetDriverByName('GTiff')
        self.raster = driver.Create('/vsimem/inmem.tif', self.sidelength, self.sidelength, 1, gdal.GDT_Float32)
        self.raster.GetRasterBand(1).WriteArray(np.random.rand(self.sidelength,self.sidelength))
        return self

    def __exit__(self, *args):
        # close file and unlink
        self.raster = None
        gdal.Unlink('/vsimem/inmem.tif')


with Raster(5) as r:
    print(r.raster)

输出:

<osgeo.gdal.Dataset; proxy of <Swig Object of type 'GDALDatasetShadow *' at 0x04564728> >

with块之外,数据集无法访问:

r.raster is None

输出:

True

如果将另一个变量绑定到r.raster,则会再次出现问题,因此您可能希望将其完全封装在Raster实例中,以及您需要的任何功能。在这一点上,你或多或少会重新发明Rasterio,但如果你的需求很简单,可能比依赖它更好。

答案 1 :(得分:1)

正如评论中所建议的,Rasterio通过rasterio.open实现了您正在寻找的行为。