使用游标访问数据

游标是一个数据访问对象,用于在表中的各个行上进行迭代或在表中插入新行。 游标有三种形式:搜索、插入和更新。 游标通常用于读取现有几何写入新几何

每种类型的游标均由对应的 ArcPy 函数(SearchCursorInsertCursorUpdateCursor)在表、表格视图、要素类或要素图层上创建而成。 可以使用搜索游标来检索行。 更新游标可用于更新和删除行,而插入游标用于在表或要素类中插入行。

游标说明

arcpy.da.InsertCursor(in_table, field_names, {datum_transformation}, {explicit})

插入行

arcpy.da.SearchCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}, {datum_transformation}, {spatial_filter}, {spatial_relationship}, {search_order})

只读访问

arcpy.da.UpdateCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}, {datum_transformation}, {explicit}, {spatial_filter}, {spatial_relationship}, {search_order})

更新或删除行

数据访问游标函数 (arcpy.da)
旧版本:

ArcGIS 10.1 中添加了一个数据访问模块 (arcpy.da)。 原始游标仍受支持;但是,新的 arcpy.da 游标的性能要快得多。 大多数情况下,帮助文档会对 arcpy.da 游标的使用进行说明。 有关经典游标模型的详细信息,请参阅 InsertCursorSearchCursorUpdateCursor 主题。

注:

游标支持图层和表格视图定义查询和选择。 游标对象仅包含地理处理工具在操作中会使用的行。

游标只能向前导航;不支持备份和检索已进行检索的行。 如果脚本需要多次遍历数据,则可能会调用游标的 reset 方法。

使用 for 循环可迭代搜索或更新游标。 同样,可通过显式使用 next 方法返回下一行以进行访问。 如果要使用游标的 next 方法来检索行数为 N 的表中的所有行,则脚本必须调用 next N 次。 在检索完结果集中的最后一行后调用 next 将返回 StopIteration 异常。

import arcpy

cursor = arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB'])
for row in cursor:
    print(row)
del cursor

搜索和更新游标同样支持 with 语句。

import arcpy

with arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB']) as cursor:
    for row in cursor:
        print(row)

从表中检索的每一行都以字段值列表的形式返回。 会按照提供给游标的 field_names 参数的相同顺序返回这些值。 游标的 fields 属性也可用于确定字段值的顺序。

游标对象

SearchCursorUpdateCursorInsertCursor 能够创建可用于遍历记录的游标对象。 多个游标函数创建的游标对象方法可能因所创创建的游标类型而有所不同。

下表显示了各个游标类型支持的方法:

游标类型方法

arcpy.da.SearchCursor

reset - 将游标重置到起始位置。

arcpy.da.InsertCursor

insertRow - 向表中插入一行。

arcpy.da.UpdateCursor

updateRow - 更新当前行。

deleteRow - 从表中删除行。

reset - 将游标重置到起始位置。

insertRow

插入游标用于创建行并插入它们。 创建游标后,insertRow 方法用于插入一组值,这些值会组成新行。 表中任何不包含在游标中的字段都将被分配字段的默认值。

import arcpy

# Create insert cursor for table
with arcpy.da.InsertCursor("c:/base/data.gdb/roads_lut", 
                           ["roadID", "distance"]) as cursor:

    # Create 25 new rows. Set the initial row ID and distance values
    for i in range(0, 25):
        cursor.insertRow([i, 100])

updateRow

updateRow 方法用于对更新游标当前所在位置的行进行更新。 从游标对象返回行后,可以根据需要对行进行修改,然后调用 updateRow 传入修改后的行。

import arcpy

# Create update cursor for feature class
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads",
                           ["roadtype", "distance"]) as cursor:
    for row in cursor:
        # Update the values in the distance field by multiplying 
        # the roadtype by 100. Road type is either 1, 2, 3 or 4.
        row[1] = row[0] * 100
        cursor.updateRow(row)

deleteRow

deleteRow 方法用于对更新游标当前所在位置的行进行删除。 提取行后,可在游标上调用 deleteRow 来删除行。

import arcpy

# Create update cursor for feature class
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads", 
                          ["roadtype"]) as cursor:
    # Delete all rows that have a roads type of 4
    for row in cursor:
        if row[0] == 4:
            cursor.deleteRow()

访问和设置字段值

对于每个游标,所使用的字段值由字段名的列表(或元祖)提供。 当从游标中返回行时,将以对应于索引位置的一组字段值的形式返回该行。

在下方示例中,将按位置访问州名称和人口计数。

import arcpy

fc = "c:/base/data.gdb/USA/States"

# Use SearchCursor to access state name and the population count
with arcpy.da.SearchCursor(fc, ['STATE_NAME', 'POP2000']) as cursor:
    for row in cursor:
        # Access and print the row values by index position.
        #   state name: row[0]
        #   population: row[1]
        print('{} has a population of {}'.format(row[0], row[1]))
提示:

尽管使用星号 (*) 可访问所有字段,但通常不建议这样做。 指定的字段越多,游标的执行速度越慢。 只列出要使用的字段会改善游标整体效率。

短整型字段值和长整型字段值以整型形式返回。 浮点型字段值和双精度字段值作为浮点型形式返回。 文本字段类型以字符串形式返回。 关于其他字段类型的详细信息如下所示。

对象标识符字段

在 ArcGIS 中创建表时,将向表中添加唯一的非空整型字段,以用作对象标识符(对象 ID)。 对象 ID 字段由 ArcGIS 维护并保证表中每行具有唯一 ID。

所有表都包括一个对象 ID 字段,该字段名称具体取决于数据类型。 OBJECTID@ 令牌也可以作为快捷键替代表中的对象 ID 字段名称。

几何字段

在 ArcGIS 中,几何数据类型用于指示表中所存储几何的类型(点、线、面、多点或多面体)。 通常(但不总是)为存储的名为 Shape几何字段。

令牌也可以替代几何字段名称以作为快捷键。 返回几何对象的 SHAPE@ 令牌可用于访问要素类几何字段,而无需提前了解字段名称。

使用搜索光标打印点要素类的 x,y 坐标。

import arcpy

infc = "c:/data/fgdb.gdb/fc"

# Enter a for loop for each feature
with arcpy.da.SearchCursor(infc, ['OID@', 'SHAPE@']) as cursor:
    for row in cursor:
        # Print the current point's object ID and x,y coordinates
        print(f'Feature {row[0]}: {row[1][0].X}, {row[1][0].Y}')

可以使用其他几何令牌访问特定几何信息。 访问完整几何往往更加耗时。 如果仅需要几何的特定属性,可以使用令牌以提供访问几何属性的快捷方式。 例如,SHAPE@XY 将返回一组代表要素质心的 x,y 坐标。

要了解有关在光标中访问几何的详细信息,请参阅读取几何写入几何

全局标识符字段

全局标识符字段(全局 ID 和 GUID)可存储注册表样式的字符串,该字符串包含用大括号括起来的 36 个字符。 这些字符串用于唯一识别单个地理数据库中和跨多个地理数据库的要素或表行。

在游标中,GUID 字段可以接受字符串和通用唯一标识符 (UUID) 值。 当读取全局 ID 和 GUID 字段时,将返回字符串。

对于全局 ID 字段,GLOBALID@ 令牌可以用作代替字段名称的快捷方式。

使用 UUID 值添加包含 GUID 字段的记录。

import arcpy
import uuid

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['guid_field']) as cursor:
    id = uuid.uuid1()
    cursor.insertRow([id])

使用字符串添加包含 GUID 字段的记录。

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['guid_field']) as cursor:
    id = '0345e170-2614-11eb-812d-f8b156b0d357'
    cursor.insertRow([id])

使用全局 ID 令牌搜索记录。

import arcpy

with arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ["GLOBALID@"], where_clause="OWNER = 'John Doe'") as cursor:
    for row in cursor:
        print(row[0])

日期字段

日期字段可存储日期、时间、日期和时间以及偏移。

在游标中,日期字段可以接受 datetime.datetime 对象或字符串值。 当读取日期字段时,返回 datetime.date 对象。

使用 datetime 对象添加包含日期字段的记录。

import arcpy
from datetime import datetime

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['date_field']) as cursor:
    # Datetime object created using constructor arguments
    date_value = datetime(2020, 7, 1, 12, 30)
    cursor.insertRow([date_value])

    # Datetime object created using fromisoformat method
    date_value2 = datetime.fromisoformat("2020-07-01 12:30:00")
    cursor.insertRow([date_value2])

使用 ISO 8601 约定和月、日、年、时间约定方式添加具有日期字段的记录。

import arcpy

dates = ["2020-07-01 12:30:45",  # ISO 8601 convention
         "July 1 2020 12:30:45", # Month day year time convention
]

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['date_field']) as cursor:
    for i in dates:
        cursor.insertRow([i])

具有高精度日期字段将以毫秒级(1/1000 秒)存储数据,而不是秒级(1/60 分钟)。 有关高精度日期字段的详细信息,请参阅将日期字段迁移至高精度工具文档。

在高精度日期字段中添加具有毫秒数据的日期。

注:

此示例中的所有值都显示为微秒值 (123456),但高精度日期字段将四舍五入为毫秒值 (123)。

impor arcpy
from datetime import datetime


dates = [datetime(2023, 8, 18, 17, 41, 13, 123456),  # datetime object
         datetime.fromisoformat("2023-08-18T17:42:15.123456"),  # datetime object from ISO 8601 string
         "2023-08-18T17:42:15.123456",  # ISO 8601 string
]

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['date_field']) as cursor:
    for i in dates:
        cursor.insertRow([i])

仅日期字段

仅日期字段可以存储日期。

在游标中,仅日期字段可以接受 datetime.date 对象或字符串值。 仅日期字段也接受 datetime.datetime 对象,但会丢弃对象的时间部分。 读取仅日期字段时,会返回 datetime.date 对象。

使用 date 对象添加包含仅日期字段的记录。

import arcpy
from datetime import date

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['date_only']) as cursor:
    date_value = date(2000, 5, 26)
    cursor.insertRow([date_value])

使用字符串值添加包含仅日期字段的记录。

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['date_only']) as cursor:
    date_value = "November 1 2015"
    cursor.insertRow([date_value])

仅时间字段

仅时间字段可以存储时间。

在游标中,仅时间字段可以接受 datetime.time 对象或字符串值。 仅时间字段也接受 datetime.datetime 对象,但会丢弃对象的日期部分。 读取仅时间字段时,会返回 datetime.time 对象。

使用 datetime.datetime 对象添加包含仅时间字段的记录。

import arcpy
from datetime import time

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['time_only']) as cursor:
    date_value = time(13, 34)
    cursor.insertRow([date_value])

使用字符串值添加包含仅时间字段的记录。

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['time_only']) as cursor:
    date_value = "16:53:45"
    cursor.insertRow([date_value])

时间戳偏移字段

时间戳偏移字段可以存储带有偏移的日期。

在游标中,时间戳偏移字段可以接受 datetime.datetime 对象。 默认情况下,如果 datetime.datetime 对象不具有时区信息,则时区将设置为 UTC。 当读取“时间戳偏移”字段时,将返回 datetime.datetime 对象。

添加包含“时间戳偏移”字段且时区为 UTC 的记录。

import arcpy
from datetime import datetime

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['timestamp_offset']) as cursor:
    date_value = datetime(2004, 12, 19, 16, 49, tzinfo=datetime.timezone.utc)
    cursor.insertRow([date_value])

添加包含带有自定义偏移的“时间戳偏移”字段的记录。

import arcpy
import datetime

tzinfo = datetime.timezone(-1 * datetime.timedelta(hours=4, minutes=15))

with arcpy.da.InsertCursor(fc, ['TIMESTAMPOFFSET']) as cursor:
    date_value = datetime.datetime(2004, 12, 19, 16, 49, tzinfo=tzinfo)
    cursor.insertRow([date_value])

BLOB 字段

二进制大对象 (BLOB) 是一种存储为长度较长的一系列二进制数的数据。 ArcGIS 会将注记和尺寸存储为 BLOB,图像、多媒体或编码的位等项也可存储在此类型的字段中。 您可以使用游标加载或查看 BLOB 字段的内容。

在游标中,BLOB 字段可以接受字符串、bytes 对象和 memoryview 对象。 当读取 BLOB 字段时,返回 memoryview 对象。

使用 .png 文件添加包含 BLOB 字段的记录。

import arcpy

data = open("c:/images/image1.png", "rb").read()
with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['imageblob']) as cursor:
    cursor.insertRow([data])

将 BLOB 字段读取为 memoryview 对象并写入 .png 文件。

import arcpy

with arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ["imageblob"]) as cursor:
    memview = cursor.next()[0]
    open("c:/images/image1_copy.png", "wb").write(memview.tobytes())

栅格字段

栅格字段格可在地理数据库中存储栅格数据或者将该数据与地理数据库一同存储。

在搜索光标中,栅格字段中的值将作为 Raster 对象读取。 更新和插入光标不支持栅格字段。

读取栅格字段并写入 .tif 文件。

import arcpy

with arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ['imag']) as cursor:
    raster = cursor.next()[0]
    raster.save("c:/images/image.tiff")

大整型字段

大整型字段可以存储 -2 53 到 253-1 之间的整数

使用大于 231 的整数添加包含大整型字段的记录。

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ["Population"]) as cursor:
    cursor.insertRow(7654321000)

游标和锁定

插入和更新游标支持 ArcGIS 应用程序设置的表格锁。 锁可以防止多个进程同时更改同一个表。 锁两种类型:共享和排他,如下所示:

  • 只要访问表或数据集就会应用共享锁。 同一表中可以存在多个共享锁,但存在共享锁时,将不允许存在排他锁。 显示要素类和预览表是应用共享锁的示例。
  • 对表或要素类进行更改时,将应用排他锁。 在 ArcGIS 中应用排他锁的示例包括:在地图中编辑和保存要素类;更改表的方案;或者在 Python IDE 中在要素类上使用插入游标。

如果数据集上存在排他锁,则无法为表或要素类创建更新和插入游标。 UpdateCursorInsertCursor 函数会因数据集上存在排他锁而失败。 如果这些函数成功地创建了游标,它们将在数据集上应用排他锁,从而使两个脚本无法在同一数据集上创建更新和插入游标。

游标支持 with 语句以重置迭代并帮助移除锁。 但是,为了防止锁定所有内容,应考虑使用 del 语句来删除对象或将游标包含在函数中以使游标对象位于作用范围之外。

编辑会话将在其会话期间对数据应用共享锁。 保存编辑内容时将应用排他锁。 如果存在排他锁,则数据集不可编辑。