第三章 处理空间数据
1.使用游标访问数据
游标是一个数据库术语,主要用于访问表格中的每一行记录或者向表中插入新的记录。在表格中,一条记录也被称为一行。游标通常用于从表格中按行读取或写入新几何结构。
游标有三种形式:搜索、插入、更新
上图为官网的描述,有关游标的具体内容可见
https://desktop.arcgis.com/zh-cn/arcmap/10.3/analyze/python/data-access-using-cursors.htm
游标只能向前导航,因此若脚本想要多次遍历,就必须重新执行游标。所以需要for循环或while循环来配合游标使用。
通过游标搜索到的记录会输出到一个字段列表中,列表内字段值的顺序和函数中field_name参数内字段值的顺序保持一致
下面是一个使用游标遍历记录的例子。该例中,遍历了GBA.shp中的类型字段
#-*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
cursor = arcpy.da.SearchCursor(fc,["类型"])
for row in cursor:
print "类型={0}".format(row[0])
值得注意的是,Python2.7版本对于中文输出存在编码不同的问题,如果字段或列表中有中文,需要在代码最前面加上前4行代码。
输出结果为
原属性表为
当然,可以进一步改进上述代码,使用with语句后,无论游标成功运行还是报错都可保证数据库锁的关闭与释放,并重置迭代。代码如下:
#-*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
with arcpy.da.SearchCursor(fc,["类型"]) as cursor:
for row in cursor:print "类型={0}".format(row[0])
注意这段代码,在使用with语句后的for循环下的print语句不能换行,如果换行就会报错。
下面将演示在某一字段下插入一个新行:
#-*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
#先把游标移到目标的字段位置
cursor=arcpy.da.InsertCursor(fc,["类型"])
#在该字段里插入新行
cursor.insertRow(["县级市"])
输出结果如图
可以发现在多了一行数据,并在“类型”字段下多了一个“县级市”
也可以通过循环来插入多行数据:
#-*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
cursor=arcpy.da.InsertCursor(fc,["类型"])
x=1
while x <= 5:
cursor.insertRow(["直辖市"])
x+=1
运行结果如图
下面代码将演示如何删除一行数据
#-*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
with arcpy.da.UpdateCursor(fc,["类型"]) as cursor:
for row in cursor:
if row[0]=="直辖市":
cursor.deleteRow()
输出结果如下
可以发现之前添加的“直辖市”的内容被删除了。
插入游标和更新游标均支持编辑操作。在ArcGIS地理处理框架中,创建游标对象的同时会在属性表上添加一个锁。这个锁能防止多个进程同时更改一个属性表。
锁有两种类型:共享锁与排它锁。
当访问表格或数据集时会应用共享锁;同一属性表中允许存在多个共享锁,但存在共享锁时将不允许存在排它锁。
当对属性表或要素类进行更改会应用排它锁;在使用游标或更新游标时都会在数据集上应用排它锁。
而在应用程序或脚本释放数据集(通过关闭或明确释放游标对象)之前,锁将一直存在。在脚本中可以使用del语句删除游标对象,否则,将会阻止所有其他程序或脚本访问该数据集。而在一个创建了插入游标或更新游标的脚本中,需要用两个del语句,一个删除行对象(del row),一个删除游标对象(del cursor)
注意:在使用with语句后可以保证数据库锁的关闭与释放,因此不需要再使用del语句。
2.在Python中使用SQL语句
通过SearchCursor函数可执行SQL查询语句,语法如下
其中可选参数where_clause表示一个SQL表达式。查询不同的数据集,where_clause参数中的SQL语句会存在细微差别,但都遵循SQL语法规则。
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
with arcpy.da.SearchCursor(fc,["Name","Classcode"],'"Classcode"=1') as cursor:
for row in cursor:
print row[0]
上述代码仅为示意。
因为SQL针对不同格式的要素有不同的语法,所以可以使用AddFieldDelimiters函数,语法如下
AddFieldDelimiters(database,field)
演示如下:
#-*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
fieldname ="类型"
delimfied=arcpy.AddFieldDelimiters(fc,fieldname)
cursor=arcpy.da.SearchCursor(fc,["市","市代码"],delimfied+"='地级市'")
for row in cursor:
print "{} {}".format(row[0],row[1])
del row
del cursor
这样就可以输出,类型是“地级市”的城市名称和城市代码,结果如下:
此外,这种SQL语句也广泛的应用于很多工具中,如select工具,其语法如下
Select_analysis (in_features, out_feature_class, {where_clause})
和SearchCursor一样,where_clause在这里就是一个SQL语句。
3.处理表和字段名
ValidateTableName函数可以用来确定某个表名在给定的工作空间中是否有效,函数语法:
ValidateTableName(name,(workspace))
函数参数是一个表名和一个工作空间路径,函数将为该工作空间返回一个有效的表名。如果表名有效则返回原始表名;如果表名无效。则其中的无效字符均用_下划线代替。
import arcpy
tablename=arcpy.ValidateTableName("Panyu","D:/PythonforArcGIS/study/shapefile/GBA")
print tablename
输出结果为
在这里Panyu是一个shp文件,能输出说明这个表名可以是数据集的名称。
下面这个例子将演示:使用CopyFeatures工具将shp从文件夹转移到另一个文件夹中。其思路为,先通过basement属性将.shp文件扩展名从文件名中移除,随后验证文件名,并将shp拷贝到另一个地理数据库中。
import arcpy
import os
from arcpy import env
env.workspace="D:\\PythonforArcGIS\\study\\shapefile\\GBA"
outworkspace="D:\\PythonforArcGIS\\study\\shapefile\\GBA2.gdb"
fclist=arcpy.ListFeatureClasses()
for shapefile in fclist:
fcname=arcpy.Describe(shapefile).basename
#先把文件名都保存到newfcname中
newfcname=arcpy.ValidateTableName(fcname)
#再通过path.join函数将新获取的文件名拼接到新文件夹的路径后面
outfc=os.path.join(outworkspace,newfcname)
#使用复制工具将shp文件转移到新文件夹中
arcpy.CopyFeatures_management(shapefile,outfc)
思路如上述代码所示,但无法输出,需要随后再调试
另外,可以将ValidateFieldName函数作为一个判断语句,只有当字段名有效情况下才能添加字段。下面这段代码将验证新字段名称的有效性,并通过AddField工具将有效字段添加到数据中。
import arcpy
fc="D:/PythonforArcGIS/study/shapefile/GBA/GBA.shp"
fieldname=arcpy.ValidateTableName("NEW")
arcpy.AddField_management(fc,fieldname,"TEXT","","",12)
输出结果如图所示
类似于ValidateTableName函数,ValidateFieldName函数也不会判断字段名是否存在,因此脚本仍然会报错,或覆盖一个已经存在的字段。
确定表名是否存在可以使用CreateUniqueName函数。使用方式为
import arcpy
from arcpy import env
env.workspace="D:/PythonforArcGIS/study/shapefile/GBA"
unique=arcpy.CreateUniqueName("GBA.shp")
arcpy.Buffer_analysis("GBA.shp",unique,"100 FEET")
因为工作空间中已有GBA,因此第一次运行输出GBA0.shp
同理,第二次运行将输出GBA2.shp
4.解析属性表和字段名
ArcGIS中的地理环境经常需要设置成要素或属性表的全限定名。而有时在处理过程中不光要知道要素的名称,还需要知道要素的路径,数据库名称以及数据的所有者。
ParseTableName函数可以将数据集中的全限定名称分割成不同的组成部分。语法如下
ParseTableName(name,(workspace))
ParseTableName返回一个由逗号隔开,并含有数据库名、所有者名以及表明的字符串。演示如下:
import arcpy
from arcpy import env
env.workspace="D:/PythonforArcGIS/study/shapefile/GBA"
fc="Panyu"
fullname=arcpy.ParseTableName(fc)
namelist=fullname.split(",")
databasename=namelist[0]
ownername=namelist[1]
fcname=namelist[2]
print databasename
print ownername
print fcname
输出结果如下,因为Panyu数据经过处理,所以没有保存数据库名、所有者名,只能输出null。