使用 with 语句关闭 GDAL 数据集
Use with statement to close GDAL datasets
考虑使用来自 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
块外调用 class 方法给出了预期的错误:
f.readlines()
ValueError Traceback (most recent call last)
in ()
----> 1 f.readlines()
ValueError: I/O operation on closed file.
现在回答我的问题:
如何使用 gdal
对象而不是文件实现相同的行为?
我有一个 class 方法,它应该从磁盘读取数据并将其放入 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 ]]
正如评论中所建议的那样,Rasterio 通过 rasterio.open
实现了您正在寻找的行为。
您不能在保留对 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,但如果您的需求很简单,那可能比依赖它更好。
考虑使用来自 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
块外调用 class 方法给出了预期的错误:
f.readlines()
ValueError Traceback (most recent call last) in () ----> 1 f.readlines()
ValueError: I/O operation on closed file.
现在回答我的问题:
如何使用 gdal
对象而不是文件实现相同的行为?
我有一个 class 方法,它应该从磁盘读取数据并将其放入 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 ]]
正如评论中所建议的那样,Rasterio 通过 rasterio.open
实现了您正在寻找的行为。
您不能在保留对 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,但如果您的需求很简单,那可能比依赖它更好。