1.GDAL库的导入

import ogr

或者:

from osgeo import ogr

万能方法:

try:
    from osgeo import ogr
except:
    import ogr

2.读取数据层

方法一:缺省方式

ogr模块内含一个ogr.Open()函数可以直接打开矢量数据,在这个过程中,ogr会自动根据文件的类型来确定相应的驱动。

inshp = r'D:\pythonlianxi\gdallianxi\Line.shp'
datasource = ogr.Open(inshp)
driver = datasource.GetDriver()              # 获取驱动
driver.name                               # ESRI Shapefile

方法二:通过驱动载入

前面已经介绍过,ogr有7个类,其中类OGRSFDriver对应于每一个所支持的矢量文件格式,要读取某种类型的数据,必须要先载入数据驱动,也就是初始化一个对象,让它“知道”某种数据结构。
数据驱动driver的Open()(方法返回一个数据源对象),其中update为0是只读,为1是可写)。例如:

Open(self, char name, int update = 0) -> DataSource

from osgeo import ogr

driver = ogr.GetDriverByName('ESRI Shapefile')
filename = r'D:\pythonlianxi\gdallianxi\Line.shp'
dataSource = driver.Open(filename,0)
if dataSource is None:
    print("could not open")
    sys.exit(1)
print("done!")

这里需要注意filename一定要写绝对路径!为了简化代码,可以使用os.chdir()进行目录切换。
使用Python的内省函数dir()可以查看datasource有哪些可用的方法

print  (dir(datasource)[:10])
['AbortSQL',
 'CommitTransaction',
 'CopyLayer',
 'CreateLayer',
 'DeleteLayer',
 'Dereference',
 'Destroy',
 'ExecuteSQL',
 'FlushCache',
 'GetDescription']

3读取图层

在GIS中,Layer(图层)由同种要素(Feature)(如点、线、多边形等)组在一起的“层”。Layer的描述与ESRI在ArcGIS中定义的模型要素类(Feature Class)一致,其对应的是要素数据集。

在《Modeling our World》中,这两个概念均有明确的阐述:

要素类:具有相同几何形状的要素的集合:点、线或多边形。我们最常见的两种要素类是简单要素类和拓扑要素类。简单要素类是指没有任何拓扑关系的点、线、多边形或注记。也就是说,一个要素类内的点与另一要素类中线要素的终点可以是一致的,但它们是不同的,其特点是可独立编辑。拓扑要素类局限在一定的图形范围内,它是一个由完整拓扑单元组成的一组要素类限定的对象。

要素数据集(要素集):具有相同坐标系统的要素类的集合。我们可以选择在要素集的内部或外部组织简单要素类,但拓扑要素类只能在要素集内部组织,以确保它们具有相同的坐标系统。
通过driver读取得到一个OGRDataSource,表示含有OGRLayer对象的一个文件或一个数据库,可以通过GetLayer进行读取

layer = dataSource.GetLayer(0)
#注意:GetLayer的参数是从0开始的。对于Shapefile而言,它只有一个图层,一般情况下这个参数都是0,如果空着,缺省情况下也是0。

3.1.数据层里面的数据量可以通过GetFeatureCount()函数获取

n = layer.GetFeatureCount()

3.2.读出上下左右边界

extent = layer.GetExtent()

3.3 查看图层属性

若想查看整个表的结构及各字段名称等信息,可在layer的附加信息里查找。

>>> layerdef = layer.GetLayerDefn()
>>> for i in range(layerdef.GetFieldCount()):
>>>     defn = layerdef.GetFieldDefn(i)
>>>     print(defn.GetName(),defn.GetWidth(),defn.GetType(),defn.GetPrecision())
id 80 4 0
level 10 12 0
source 80 4 0
parent_id 10 12 0
sibling_id 10 12 0
area 19 2 11
Shape_Leng 19 2 11
Shape_Area 19 2 11

这就是整个表的结构。 当然类型是枚举类型,若要查看数据类型名,可对应地建立一个数据类型字典

4.获取要素(Feature)信息

在Shapefile中,要素模型由点、线、面三种类型构成。要素类自带属性信息,一般对应属性表中的一行。

Layer的核心是针对Feature的操作。GetFeatureCount()GetFeature()GetNextFeature()可获取层内所有的要素;GetFeaturesRead()可查询目前已读取了多少条Feature;生成器可读取要素值;若要再次访问获取过的要素,可访问ResetReading()从头读取

4.1读取某一要素feature

feat = layer.GetFeature(41)
fid = feat.GetField('id')
print(fid)
feat = layer.GetFeature(0)
fid = feat.GetField('id') #should be a different id
print(fid)

4.2按顺序读取feature,循环遍历所有的feature

feat = layer.GetNextFeature()  #读取下一个
while feat:
    feat = layer.GetNextFeature()
later.ResetReading()  #复位

4.读取要素

一个完整的feature包括一个geometry和geometry的一系列属性

4.1读取要素属性

>>> layer.ResetReading()
>>> feat=layer.GetFeature(0)
>>> feat.keys()
['id',
 'level',
 'source',
 'parent_id',
 'sibling_id',
 'area',
 'Shape_Leng',
 'Shape_Area']
>>> feat.GetField('level')
1

可以使用feature.GetField('CNTRY_NAME')来获取字段的值。字段的名称,在上节图层属性中获取,也可以使用要素keys()方法获取。
除了使用字段名称之外,还可以使用索引值来获取要素属性。下面是对所有的属性值进行遍历:

>>> for i in range(feat.GetFieldCount()):
>>>      print(feat.GetField(i))
0-E
1
WVS
-1
0
50654050.6945
2284.13578022
6280.55928902

此操作列出的是这个要素的所有属性值。

4.2 读取要素几何

>>> geom = feat.GetGeometryRef()
>>> geom.GetGeometryName()
'POLYGON'
>>> geom.GetGeometryCount()
326
>>> geom.GetPointCount()
0
>>> geom.ExportToWkt()[:80]
'POLYGON ((107.544833 76.914028,106.533222 76.499556,111.093417 76.7653890000001,'

这是Geometry的主要操作方法。需要注意的是如果Geometry类型是多边形,那么就有两层Geometry,获取多边形后,还需要获取构成多边形边缘的折线,才可以读取构成多边形的点。如果类型是单线或者点,就可以直接用GetX(), GetY(),而不用再多花一步GetGeometryRef()来获取子形状了。

>>> polygon=geom.GetGeometryRef(0)
>>> polygon.GetGeometryName()
'LINEARRING'
>>> polygon.GetGeometryCount()
0
>>> polygon.GetPointCount()
1004
>>> polygon.GetX(0)
107.54483300000004
>>> polygon.GetY(0)
76.91402800000003
>>> polygon.GetZ(0)
0.0
>>> polygon.ExportToWkt()[:80]
'LINEARRING (107.544833 76.914028,106.533222 76.499556,111.093417 76.765389000000'

这些点都是地理意义上的坐标点,单位是根据空间参考决定的(此数据的单位应该是经纬度,而不是投影坐标的单位米)。获取了这些坐标后,不需要像栅格数据那样用四周边界点来计算地理坐标,矢量数据可直接铺展到一个实际平面已经定义好的投影或者地理坐标系上。

栅格数据有像元长宽,并且有数据意义上的行列坐标,而矢量在没有贴到某个实际存在的物体表面-如计算机屏幕或者打印的纸张之前,是无法表示数据意义上的长宽,所以比例尺对于矢量数据来说,没有绘制操作也就无根本意义。

5.空间参考

矢量数据的空间参考信息可从每个要素中获取。ShapeFile的坐标系统和仿射参数是分开的,通过.prj附加在shp文件同目录下的方式来获取坐标系统,而仿射参数是直接放在ShapeFile文件内部的,只不过它和GeoTiff的tfw不一样,它表示一个外包矩形,记录的是整个layer的地理范围。

>>> from osgeo import ogr
>>> inshp = '/gdata/GSHHS_c.shp'
>>> datasource = ogr.Open(inshp)
>>> layer = datasource.GetLayer(0)
>>> layer.GetSpatialRef()
>>> layer.GetExtent()
(-180.0, 180.00000000000023, -89.99999999999994, 83.53036100000006)

除了整个图层有地理范围外,每个要素(feature)也有地理范围,可通过GeometryDef来获取这个地理范围:

>>> feature = layer.GetFeature(0)
>>> geom = feature.GetGeometryRef()
>>> geom.GetEnvelope()
(-9.500388999999927, 180.0000000000001, 1.2695000000000505, 77.71625000000006)
>>> geom.GetSpatialReference()
>>> dir(geom)[:6] + ['... ...'] + dir(geom)[-3:]
['AddGeometry',
 'AddGeometryDirectly',
 'AddPoint',
 'AddPointM',
 'AddPointZM',
 'AddPoint_2D',
 '... ...',
 '__weakref__',
 'this',
 'thisown']

这里获取的外包矩形只针对于这个要素,而不是整个图层。

6.释放内存

在读取完数据之后,应保持良好习惯,释放数据,及时清理操作所占内存。
释放内存需要将要素的资源释放,使用Destroy()函数。

feature.Destroy()

关闭数据源,相当于文件系统操作中的关闭文件

dataSource.Destroy()