ArcPy的数据访问模块arcpy.da,可以控制会话、编辑操作、游标、表或要素类与NumPy数组之间相互转换的函数以及对版本化和复本工作流的支持。
1.使用游标访问数据
游标是一个数据库术语,它主要用于访问表格中的每一行记录或者向表中插入新的记录。在ArcGIS中,游标通常用于从表中或向表中按按行读取或写入新几何结构。
游标有三种:搜索、插入和更新。这三种游标的功能如下:
a)搜索游标可用于检索行
b)插入游标可用于向表或要素类中插入行。
c)更新游标可用于根据位置更新和删除行。
每种类型的游标均由arcpy.da模块中对应的ArcPy函数(SearchCursor、InsertCusor和UpdateCursor)创建。所有这三种游标可以在表、表格试图、要素类或要素图层上进行操作。全部三个游标函数均可创建用于访问每一行记录的游标对象。游标对象支持的方法取决于游标的类型。
游标只能向前导航。如果脚本需要多轮次遍历数据,应用程序必须重新执行游标函数。搜索或更新游标可以通过for循环或者while循环,并使用游标的next方法遍历每一行记录。如果要在游标上使用next方法来检索行数为n的表中所有记录,脚本必须反复调用next方法n次。当游标遍历到最后一行是,再次调用next函数会出现一个StopIteration异常。
这三种游标都有两个必选参数:输入表和字段名称列表。搜索和更新游标还有几个可选参数。调用三个游标的语法如下:
arcpy.da.InsertCursor(in_table, field_name)
arcpy.da.SearchCursor(in_table, field_name, {where_clause}, {spatial_reference}, {explore_to_points})
arcpy.da.UpdateCursor(in_table, field_name, {where_clause}, {spatial_reference}, {explore_to_points})
通过游标搜索得到的记录将会输出到一个字段列表中,列表内字段的顺序和函数中field_name参数内字段值的顺序一致。
下面是一个使用搜索游标遍历表中所有记录,并输出指定字段的例子。
import arcpy
fc = "C:/Data/study.gdb/roads"
cursor = arcpy.da.SearchCursor(fc, {"STREETNAME"})
for row in cursor:
print "Streetname = {0}".format(row[0])
2.1.with语句
搜索和更新游标还支持with'语句
。使用with语句可以保证数据库锁的关闭和释放,并充值迭代。
import arcpy
fc = "C:/Data/study.gdb/roads"
with arcpy.da.SearchCursor(fc, {"STREETNAME"}) as cursor:
for row in cursor:
print "Streetname = {0}".format(row[0])
2.2插入对象
使用InsertCursor函数创建一个游标对象,然后使用insertRow函数在新的一行中插入数据。
import arcpy
fc = "C:/Data/study.gdb/roads"
cursor = arcpy.da.InsertCursor(fc, {"STREETNAME"})
cursor.insertRow(["NEW STREET"])
默认情况下,新插入的数据位于表末尾。表中游标没有遍历到的字段会分配为默认值,通常为“null”。
2.3更新对象
更新游标可根据游标的位置更新和删除行。updateRow方法用于对行对象进行更新。
下面的例子中,游标对象通过UpdateCursor函数创建。在for循环中,一个字段(Acres)的值会根据另一个字段(Shape_Area)的值进行更新。
import arcpy
fc = "C:/Data/study.gdb/roads"
cursor = arcpy.da.UpdateCursor(fc, {"ACRES", "SHAPE_AREA"})
for row in cursor:
row[0] = row[1] / 43560
cursor.updateRow([row])
2.4删除对象
deleteRow方法用于删除UpdateCursor当前位置所在的行对象。提取行对象后,可在游标上调用deleteRow方法删除行,代码如下
import arcpy
fc = "C:/Data/study.gdb/roads"
cursor = arcpy.da.UpdateCursor(fc, ["STREETNAME"])
for row in cursor:
if row[0] == "MAIN ST":
cursor.deleteRow()
2.5删除排他锁
使用del语句可以删除游标对象,以便释放该游标对象设置在数据集上的排他锁。
例如:
import arcpy
fc = "C:/Data/study.gdb/roads"
cursor = arcpy.da.UpdateCursor(fc, ["STREETNAME"])
for row in cursor:
if row[0] == "MAIN ST":
cursor.deleteRow()
del row
del cursor
使用with语句可以保证数据锁的关闭和释放。因此使用了with’语句后,就不需要在使用del语句。
3.在Python中使用SQL
在地理处理中,经常需要使用结构化查询语言(SQL)查询数据。ArcMap里的按属性选择功能就需要使用SQL,ArcToolBox里面的很多工具也需要用到SQL。
在Python中使用SearchCursor函数可以执行SQL查询语句。SearchCursor的语法如下:
SearchCursor(in_table, field_name, {where_clause}, {spatial_reference}, {fields}, {explode_to_points})
其中可选参数where_clause表示一个SQL表达式。查询不同的数据集,where_clause参数中的SQL语句会存在细微差别,但是都遵循SQL的语法规则。
下面是一段使用SQL表达式的代码:
import arcpy
fc = “C:/Data/study.grd/roads”
cursor = arcpy.da.SearchCursor(fc, ["NAME", "CLASSCODE"], ' "CLASSCODE" = 1 ')
for row in cursor:
print row[0]
del row
del cursor
3.1AddFieldDelimiters
**SQL的语法是比较繁琐,因为针对不同格式的要素,会有不同的语法。**例如,shapefile和文件地理数据库中要素类的字段分隔符是两个引号(“”),个人地理数据库的字段分隔符是中括号([]),ArcSDE地理数据库中要素类没有分隔符。为了防止混淆并确保分隔符的准确性,可以使用AddFieldDelimiters
函数,其语法如下:
AddFieldDelimiters(datssource, field)
该函数可以识别正在使用的数据集类型,然后添加正确的分隔符。
import arcpy
fc = "C:/Data/zipcodes.shp"
fieldname = "CITY"
delimfield = arcpy.AddFieldDelimiters(fc, fieldname)
cursor = arcpy.da.SearchCursor(fc, ["NAME", "CLASSCODE"], delimfield + '' = 'LONGWOOD' ")
for row in cursor:
print row[0]
def row
del cursor
3.2 Select_analysis
SQL表达式在其他函数中也很常见。很多内置工具也使用SQL语句,例如Select工具。
Select_analysis(in_features, out_feature_class, where_clause)
下面的例子使用了AddFieldDelimiters函数:
import arcpy
infc = "C:/Data/zipcodes.shp"
fieldname = "CITY"
outfc = "C:/Data/zip_select.shp"
delimfield = arcpy.da.AddFieldDlimiters(infc, fieldname)
arcpy.Select_analysis(infc, outfc, delimfield + " = 'LonGWOOD' ")
4.处理表和字段名
在处理不同的数据集时,要确保每个属性表和字段都有一个有效且唯一的名称,特别是在处理地理数据库中创建数据时。
4.1ValidateTableName
ValidateTableName函数可以用来确定某个表明在给定的工作空间中是否有效,函数语法如下:
ValidateTableName(name, {workspace})
函数的参数是一个表名和一个工作空间路径,函数将为该工作返回一个有效的表名。如果表名原本就是有效的,那么函数就会返回原始的表名。如果表名是无效的那么无效的字符都用下划线(__)代替。
例如,下面的代码用于确定在一个名为study的文件地理数据库中,表名all roads是否有效。
import arcpy
tablename = arcpy.ValidateTableName("all roads", "C:/Data/study.gdb")
print tablename
在这个例子中,all_roads作为表名返回。下划线(__)被添加到表名中,因为表名不可以包含空格。
下面的代码使用CopyFeature
工具将所有的shapefile从文件夹转移到地理数据库中。首先通过basename属性吧”.shp“文件扩展名从文件名中移除,随后验证文件名,并将shapefile拷贝到地理数据库的要素中。代码如下:
import arcpy
import os
from arcpy import env
env.workspace = "C:/Data"
outworkspace = "C:/Data/test/study.gdb"
fclist = arcpy.ListFeatureClasses()
for shapefile infclist:
fcname = arcpy.Describe(shapefile).basename
newfcname = arcpy.ValidateTableName(fcname)
outfc = os.path.join(outworkspace, newfcname)
arcpy.CopyFeatures_mangagement(shapefile, outfc)
4.2ValidateFieldName
可以使用ValidateFieldName
函数对字段名进行类似的操作。只要在字段名有效的情况下,才能添加字段。因为需要先验证字段名是否有效,否则脚本可能会报错。函数语法如下:
ValidateFieldName(name, {workspace})
下面的代码将验证新字段名称的有效性,并通过AddField工具将有效字段添加到数据中。所有无效字符都会被下划线代替。
import arcpy
fc = "C:/Data/roads.shp"
fieldname = arcpy.ValidateFieldName("NEW%^")
arcpy.AddField_management(fc, fieldname, "TEXT", "", "", 12)
在这个例子中,字符串”NEW^%“被”NEW_“代替。
4.3CreateUniqueName
CreateUniqueName函数通过在输入名称后追加数字的方式指定工作空间创建唯一名称,该数字会不断增大,直到名称是唯一的为止。该函数仅可以在工作空间内创建唯一的表名,而无法处理字段名。应用该函数代码如下:
import arcpy
from arcpy import env
env.workspace = "C:/Data"
unique_name = arcpy.CreateUniqueName("buffer.shp")
arcpy.Buffer_analysis("roads.shp", unique_name, "100 FEET")
代码第一次运行时,文件buffer,shp不存在,得到的要素名称为buffer.shp,第二次运行时,buffer.shp存在,得到的要素名称为buffer0.shp。
5.解析属性表和字段名
ArcGIS中的地理处理环境经常需要设置成要素或属性表的全限定名。ParseTableName函数可以将数据集中的全限定名称分割为不同的组成部分。该函数的语法如下:
ParseTableName(name, {workspace})
ParseTableName函数返回一个逗号隔开,并含有数据库名、所有者名以及表名的字符串。下面的代码使用ParseTableName函数将一个要素类的全限定名分割开来,并将每个部分存入到列表中:
import arcpy
from arcpy import env
env.workspace = "C:/Data/study.gdb"
fc = "roads"
fullname = arcpy.ParseTableName(fc)
namelist = fullname.split(", ")
databasename = namelist[0]
ownername = namelist[1]
fcname = namelist[2]
print databasename
print ownername
print fcname
与ParseTableName函数类似,ParseFieldName函数可以将表中某个字段的全限定名分割成不同的部分。该函数将返回一个由逗号隔开,并含有数据库名、所有者表名以及字段名的字符串。
6.处理文本文件
Python可以读取文本文件的内容,并提供给ArcGIS使用。使用open函数打开文件,语法如下:
open(name, {mode}, {buffering})
open函数仅有一个必选参数,即文件名,该函数将会返回一个对象。下面的代码从磁盘上打开了一个现有的文件:
f = open("c:/Data/sample.txt")
只使用文件名作为参数只能返回一个只读的文件对象。如果想做其他操作,必须明确指定一张访问模式。最常见的访问模式由如下几种:
缓存文件参数可以决定是否需要进行缓存。默认情况下不进行缓存,当缓存参数设置为true时,Python使用内存代替磁盘来提高读写速率,对于数据量不大的文件,一般不需要设置缓存参数。
还有几种处理文件的函数分别是write、read、close,其示例如下:
f = open("c:/Data/mytext.txt", "w")
f.write("Geographic Information System")
f.close()
运行上面的代码会创建一个新的文件对象,如果文件已存在就会重写这个已有的文件。write函数用来写入字符串,close函数用来关闭文件并保存文件内容。
读取文件的代码如下:
f = open("C:/Data/mytext.txt")
f.read()
read函数可以读取文件内容,没有设置参数时,默认读取整个文件的内容,也可以通过设置一个值来限定读取字符的个数,例如:
f = open("C:/Data/mytext.txt")
f.read(3)
文件被打开后,读取其中的字符串是单向进行的。当再次使用read函数时,脚本会从上次读取结束的位置继续读取。
可以通过seek函数来设置当前读取文件的位置,从而不需要再重新打开这个文件。例如:
f.seek(0)
f.read(10)
6.1 readline和readlines
使用readline方法,每次读取一行并以字符串形式返回。继续调用readline函数会读取下一行,该函数通用会返回分隔符(\n)。
使用readlines方法可以读取所有行,并以列表的形式返回。
6.2writelines
write和writelines可以创建一个多行的文件。添加新行时,需要使用分隔符(\n)。
f = open("C:/Data/tintext.txt", "w")
f.write("Triangulated\nIrregular\nNode")
f.close()
writelines方法可以用来修改字符串中指定的某一行。
6.3遍历文件
可以通过read或者readlin方法遍历,例如:
``
f = open("C:/Data/mytext.txt")
while True:
line = f.readline()
if not line: breadl
<function>
f.close()
<function>
表示对每一个字符进行相关处理.
使用read或readlines方法会占用相当多的内存。此时可以while循环下使用read,也可以使用fileinput模块代替open函数。该模块可以将文件中的内容创建成一个对象,然后就可以使用for循环迭代处理该对象内每一行的内容,例如:
import fileinput
for line in fileinput.input("C:/Data/mytext.txt")
<function>
下面的脚本首先以read模式打开一个已有的文件,然后write模式中创建了一个新的文件,for循环用来迭代每一行,replace方法调用删除指定的字符串,处理后的结果输出到新的文件中。
input = open("C:/Data/coordinates.txt")
output = open("C:/Data/coordinates_clean.txt","w")
for line in input:
str = line.replace("ID: ", "")
output = write(str)
input.close()
output.close()
``