背景
1、什么是游标(cursor)?
游标是包含从要素类或表中获取的一行或多行数据的内存对象。每行数据包含了数据源中每个字段中的属性以及每个要素的几何信息。游标可对表和要素类的数据进行搜索,增加,插入,更新以及删除。
2、ArcPy数据访问模块(arcpy.da
)是ArcGIS10.1新引入的模块,该模块包含的方法可迭代游标对象中的行。你还可以创建多种形式的游标。比如,搜索游标用于读取行数据。更新游标可用于更新行数据以及删除行,插入游标可用于插入新行。
3、arcpy.da
提供了三个游标函数。每个游标函数都会返回一个与该函数同名的游标对象。
SearchCursor()
函数创建一个只读的搜索游标(SearchCursor
)对象,该对象包含了表或要素类中的数据。
InsertCursor()
函数创建一个插入游标(InsertCursor
)对象,该对象可用于向表或要素类插入行。
UpdateCursor()
函数创建一个更新游标(UpdateCursor
)对象,该对象可用于编辑或删除表和要素类中的数据。每一个游标对象都提供了访问游标中行数据的方法。
如果在with语句内使用游标,锁定将在数据处理后自动释放。但在ArcGIS10.1以前的版本中,游标需要使用python的del语句手动释放。
在使用包含InsertCursor和UpdateCursor的python脚本之前,先关闭ArcMap和ArcCatalog,以防数据源已经被其它应用程序锁定,python代码将不能访问数据。
示例
1、使用搜索游标(SearchCursor)访问要素类中的要素
(1)案例:如何在一个搜索游标(SearchCursor
)对象中访问表或要素类的行数据:
import arcpy.da
arcpy.env.workspace="C:/ArcpyBook/Ch8"
with arcpy.da.SearchCursor("Schools.shp",("Facility","Name")) as cursor:
for row in sorted(cursor):
print "School name:"+row[1]
代码解释:
与SearchCursor()
函数一起使用的with
语句将会创建游标,打开游标并关闭游标。因此你就不必像ArcGIS10.1之前版本那样关注游标锁的释放问题。
传递给SearchCursor()
函数的第一个参数是一个要素类,这里指Schools.shp
文件。第二个参数是一个包含了我们想要返回游标中的字段名称的元组。出于性能考虑,最好控制仅返回游标对象中那些你需要用来完成任务的字段。本案例中,我们仅指定返回Facility
和Name
字段。搜索游标(SearchCursor
)对象保存在cursor
变量中。
在with
语句块中,我们使用了Python的for
循环语句来循环返回的每一个学校数据。我们还使用了Python中的sorted()
函数来对游标中的内容进行排序。你只要简单地使用代表你想要返回的字段的索引数就可以获取该字段值。在本案例中,我们想要返回Name
列中的内容,相对应的索引数为1
,也就说返回的字段名称元组中的第二个元素项。
(2)使用where条件语句筛选记录
默认情况下,搜索游标(SearchCursor
)会包含表或要素类中的所有行。不过很多情况下,你想按照一定的条件来限制返回的行数。通过使用where
条件语句指定一个筛选器来限制返回到记录。
import arcpy.da
arcpy.env.workspace="G:/ArcpyBook/Ch9"
with arcpy.da.SearchCursor("Schools.shp",("Facility","Name"),'"Facility"=\'HIGH SCHOOL\'') as cursor:
for row in sorted(cursor):
print "High School name:"+row[1]
其中在SearchCursor()
函数中添加where
语句来查询Facility
字段中包含文本“HIGH SCHOOL”
的记录。
(3)使用几何令牌(Geometry tokens)改进游标性能
- 几何令牌(Geometry tokens)是ArcGIS10.1引入用来改进游标性能。使用几何令牌允许只返回部分几何信息而不用返回整个几何对象。由于返回数据量的原因,返回要素的完整几何对象会降低游标性能。而仅返回需要的几何信息则速度明显快很多。
- 令牌是以
SHAPE@<要返回的要素几何信息>
的格式作为字段列表中的字段来传递给游标构造函数。OID@令牌是唯一的例外,该令牌返回要素的对象ID。下面的代码示例用来访问要素的质心X,Y坐标:
with.arcpy.da.SearchCursor(fc,("SHAPE@XY","Facility","Name"))as cursor:
在本案例中,将使用几何令牌来提高游标的性能。你将获取parcels
要素类中每一个地块的质心XY坐标以及一些其他属性信息。
import arcpy.da
import time
arcpy.env.workspace="G:/ArcpyBook/Ch9"
#添加一个开始时间
start=time.clock()
#使用with语句来创建一个游标,该游标包含每一个要素的质心坐标以及存储在PY_FULL_OW字段中的所有者信息
with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@XY")) as cursor:
for row in cursor:
print "Parcel owner:{0} has a location of:{1}:".format(row[0],row[1])
#计算运行时间
elapsed = time.clock()-start
print "Execution time:"+str(elapsed)
几何令牌可以作为游标构造函数中的一个字段名称来使用。这些令牌仅返回部分几何信息而不用返回完整的几何信息,因此使用几何令牌用于提升游标性能。这将会显著提升游标性能,尤其是处理大数据量的线或面数据集。如果只需要游标对象中的特定的几何信息,那你应该使用几何令牌。
现在,我们计算返回完整几何对象的的运行时间:
在SearchCursor()
函数使用SHAPE@
替换SHAPE@XY
来返回完整几何信息:
with arcpy.da.SearchCursor("coa_parcels.shp",("PY_FULL_OW","SHAPE@")) as cursor:
运行脚本。你会看到下面的输出结果。你的时间会跟我的不一样,不过注意执行时间变的慢了一些。在本案例中,由于我们仅返回了2600个元素运行时间只慢了一秒多。如果要素类的数据量足够大,运行时间的差异会加大:
2、使用插入游标(InsertCursor)插入行
InsertCursor()
函数可用于创建插入游标(InsertCursor
)对象,该游标对象可以通过程序向要素类和表中添加新行。insertRow()
方法可向插入游标(InsertCursor
)对象中添加新行。行以列表或元组的形式传递给insertRow()
方法。列表中的值需与插入游标对象创建时定义的字段值一致。
同其他类型的游标一样,你还可以使用该方法中的第二个参数来限制返回的字段名称。InsertCursor()
函数也支持几何令牌。
(1)本案例中,我们要在California
要素类中插入两个新的火情点数据。要插入的行数据需要保存在一个列表变量中。之后,在构造函数中使用要素类和字段参数创建一个插入游标对象。最后,调用insertRow()
方法向要素类中插入新行:
import arcpy.da
rowValues = [('Bastrop','N',3000,(-105.345,32.234)),('Ft Davis','N',456,(-109.456,33.468))]
fc = "G:/ArcpyBook/data/Wildfires/WildlandFires.mdb/California"
fields = ["FIRE_NAME","FIRE_CONTAINED","ACRES","SHAPE@XY"]
with arcpy.da.InsertCursor(fc,fields) as cursor:
for row in rowValues:
cursor.insertRow(row)
(2)在本案例中,我们将火情发生位置点添加到一个当空的点要素类中。此外,你还会使用Python的文件操作方法从文本文件中读取坐标数据。
import arcpy
import os
arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
f = open("C:/ArcpyBook/Ch8/WildfireData/NorthAmericaWildfires_2007275.txt","r")
lstFires = f.readlines()
try:
with arcpy.da.InsertCursor("FireIncidents",("SHAPE@XY","CONFIDENCEVALUE")) as cur:
cntr = 1
for fire in lstFires:
if 'Latitude' in fire:
continue
vals = fire.split(",")
latitude = float(vals[0])
longitude = float(vals[1])
confid = int(vals[2])
rowValue = [(latitude,longitude),confid]
cur.insertRow(rowValue)
print("Record number " + str(cntr) + " written to feature class")
cntr = cntr + 1
except Exception as e:
print(e.message)
finally:
f.close()
其中按照插入游标(InsertCursor)创建时定义的字段顺序将这些值放入一个叫做rowValue
的列表变量中。即经纬度值对放在前面,之后是可信度值。
3、使用更新游标(UpdateCursor)更新行
如果需要编辑或删除表或要素类中的行数据,你可以使用更新游标(UpdateCursor
)。同插入游标(InsertCursor
)一样,更新游标(UpdateCursor
)中的数据内容可以通过使用where
条件语句来控制。
本案例中,我们将会在脚本中使用更新游标(UpdateCursor
)来更新FireIncidents
要素类中的每一个要素,我们会添加一个对可信度值描述性更强的字段并赋值poor
,fair
,good
或excellent
。更新字段值之前,脚本会先向FireIncidents
要素类中添加一个新字段。
import arcpy
arcpy.env.workspace = r"G:\ArcpyBook\data\Wildfires\WildlandFires.mdb"
try:
arcpy.AddField_management("FireIncidents","CONFID_RATING","Text",10)
print "CONFID_RATING field added to FireIncidents"
with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
cntr = 1
for row in cursor:
if row[0] <= 40:
row[1] = 'POOR'
elif row[0] > 40 and row[0] <= 60:
row[1] = 'FAIR'
elif row[0] > 60 and row[0] <=85:
row[1] = 'GOOD'
else:
row[1] = 'EXCELLENT'
cursor.updateRow(row)
print "Record number " + str(cntr) + " updated"
cntr = cntr + 1
except Exception as e:
print e.message
注意:在非编辑会话状态下对游标对象中所执行的插入,更新和删除操作是不能恢复的。不过,ArcGIS10.1支持编辑会话状态下的游标功能,也就意味着你可以在编辑状态下完成这些操作来避免不能恢复的问题。我们会在后面介绍编辑会话相关内容。
4、使用更新游标(UpdateCursor)删除行
注意:非编辑会话状态下的删除行操作是不可恢复的。
更新游标(UpdateCursor
)除了可以更新记录,还可以删除表或要素类中的行。更新行和删除行操作中,创建更新游标(UpdateCursor
)的方式都是相同的,不过删除行操作不调用updateRow()
方法,而是调用deleteRow()
方法。你也可以使用where
条件语句来限制返回的记录。在本案例中,我们将使用一个通过where
条件语句筛选的更新游标(UpdateCursor
)来删除FireIncidents
要素类中的记录。
import arcpy
arcpy.env.workspace = r"G:\ArcpyBook\data\Wildfires\WildlandFires.mdb"
try:
with arcpy.da.UpdateCursor("FireIncidents",("CONFID_RATING"),'[CONFID_RATING]=\'POOR\'') as cursor:
cntr = 1
for row in cursor:
cursor.deleteRow()
print "Record number " + str(cntr) + " deleted"
cntr = cntr + 1
except Exception as e:
print e.message
思路:要素类和表中的行可以调用更新游标(UpdateCursor)中的deleteRow()方法来删除。在本案例中,我们在更新游标(UpdateCursor)构造函数中使用了where条件语句来限制仅返回CONFID_RATING字段值为POOR的记录。我们之后循环遍历游标中返回的记录并调用deleteRow()方法来删除行。
5、编辑会话中插入行并更新行
前面的几个示例已经使用了插入游标和更新游标向表和要素类中添加数据,编辑数据和删除数据。只是脚本执行完成后,这些更改都是永久性且不可恢复的。
数据访问模块中新的Editor
类支持创建编辑会话和编辑操作。编辑会话中,要素类和表的更改在调用特定方法来保存应用修改之前的临时数据。这一点与ArcGIS桌面软件中的编辑工具的功能相同。
编辑会话是通过调用初始化会话的Editor.startEditing()
方法开始。在编辑会话中,你通过调用Editor.startOperation()
方法开始执行编辑操作。之后你可以执行各种操作来编辑你的数据。这些编辑结果可以执行恢复,重做和中止操作来回滚,向前滚动和取消编辑操作。操作完成后,你可以调用Editor.stopOperation()
方法,紧接着调用Editor.stopEditing()
方法。编辑回话的处理过程如下图所示:
你可以退出会话而不保存所做的修改。在这种情况下,这些修改不会保存。编辑会话允许在会话内执行操作并可以将修改永久保存到数据库中或是回滚。此外Editor
类还支持撤销和重做操作。
import arcpy
import os
arcpy.env.workspace = "C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb"
try:
edit = arcpy.da.Editor('C:/ArcpyBook/Ch8/WildfireData/WildlandFires.mdb')
edit.startEditing(True)
with arcpy.da.UpdateCursor("FireIncidents",("CONFIDENCEVALUE","CONFID_RATING")) as cursor:
cntr = 1
for row in cursor:
# update the confid_rating field
if row[0] > 40 and row[0] <= 60:
row[1] = 'GOOD'
elif row[0] > 60 and row[0] <= 85:
row[1] = 'BETTER'
else:
row[1] = 'BEST'
cursor.updateRow(row)
print("Record number " + str(cntr) + " updated")
cntr = cntr + 1
edit.stopEditing(True)
except Exception as e:
print(e.message)
编辑操作应该在编辑会话内进行,使用Editor.startEditing()方法启动编辑会话。startEditing()方法有两个可选参数:with_undo和multiuser_mode。with_undo参数的数据类型是布尔型,值为true或false,默认值为true,当设置为true,将创建一个撤销/重做堆栈。multiuser_mode参数的默认值为true,当它为false试,可获得编辑非版本化或版本化数据集的全部权限。如果数据集是非版本化的,使用stopEditing(False)不会提交编辑,而当stopEditing()设置为true时编辑将会提交。Editor.stopEditing()方法的参数为true或false,表示是否保存更改,默认值为true。
6、读取要素类的几何信息
Arcpy中与要素类有关的几何对象包括Polygon
,Polyline
,PointGeomtry
以及MultiPoint
,这些对象都可以通过游标来访问。几何对象与要素类中shape字段有关。你可以通过几何对象来读取要素类中每一个要素的几何信息。
- 线(
polyline
)与面(polygon
)要素类由包含了多个部分的要素组成。你可以调用partCount
属性来返回每个要素的部分数量然后对每个部分调用getPart()
来循环遍历每个点并提取坐标信息。
- 点(
point
)要素类由包含了每个点坐标信息的要素组成,每个要素对应一个PointGeometry
对象。
本案例中,你将使用搜索游标(SearchCursor
)对象和Polygon
对象来读取一个面要素类的几何信息。
#
#先创建一个搜索游标对象来保存要素类内容。之后使用for语句循环遍历游标内的每一行。
#对于每一行数据,我们再次循环遍历所有的几何部分。
#对于每个部分,我们返回每个部分相关的点并打印每个点的x,y坐标信息。
#
import arcpy
infc = r"G:\ArcpyBook\data\CityOfSanAntonio.gdb\SchoolDistricts"
#基于输入要素类创建搜索游标(SearchCursor)对象,并返回ObjectID和Shape字段。
#Shape字段包含了每个要素的几何信息。
with arcpy.da.SearchCursor(infc,["OID@","SHAPE@"]) as cursor:
for row in cursor:
print "Feature {0}:".format(row[0])
partnum = 0
for part in row[1]:
print "Part {0}".format(partnum)
for pnt in part:
if pnt:
print "{0},{1}".format(pnt.X,pnt.Y)
else:
print "Interior Ring"
partnum += 1
参考资料
https://www.jianshu.com/p/3898f35a1085
案例数据
链接:https://pan.baidu.com/s/1-Ug2g2aYvrQYR1qmPpsn_g 密码:hcrs