搜罗全网!ArcGIS二次开发Python(arcpy)指南(二):超详细文件存取指南 有这一篇就够了
前言:ArcPy 对数据的存取有好几种情况,本篇文章将详细说清楚所有情况,同时针对矢量数据、栅格、数据库甚至 CAD 文件都有演示,包教包会,最后也有源码和pdf手册下载,收藏我这一篇就够了!
第一步当然是打开、修改、保存文件咯,开篇就先讲这个。本篇文章不会深入到文件数据内部的一个要素、一个点、一个像素元的操作,而是各种文件层面的操作。使用 Python 调用 arcpy 添加、修改、保存文件数据在不同的应用场景下有不同的方式;笔者根据使用 ArcPy 存取数据时是独立的,还是需要对 mxd 文件进行操作做了分类,有了下面这个树状图,该篇文章也是按照这个分节的,正好3大节,读者把这个思路理清就没问题了,很简单!
独立处理数据
独立的数据处理就比较纯粹了,完全不涉及到 mxd 文件。1.读取 SHP 文件Chapter2/code1.py 文件的代码如下:# -*- coding:utf-8 -*-import arcpyimport oscws = os.getcwd()# 设置工作空间arcpy.env.workspace = cws# 可以覆盖同名文件arcpy.env.overwriteOutput = Truearcpy.CopyFeatures_management("../SHP/Boroughs.shp", "out.shp")CopyFeatures_management 函数:将输入要素类或图层复制到新要素类。该方法常用于保存矢量文件。上面的示例代码就是将 Boroughs.shp 另存为 out.shp 文件。可以看到,读取矢量数据非常简单,直接输入矢量文件的地址即可。这里只是一个简单的演示,仅仅是读取 shp 文件然后再导出,在实际生产中,读取数据后通常需要进行一定的处理操作,然后才是导出,但是现在仅做展示,所以简化了流程。Note:使用 arcpy.CopyFeatures_management 前请一定要配置工作空间 arcpy.env.workspace,就像示例文件一样,不然很有可能运行报错。2.读取数据库文件GDB 数据库是 Esri 官方出品的地理空间数据库。如果直接在 Windows 资源管理器中打开该数据库的话是无法看到具体内容的,只能看到类似这样的文件:
那么如何读取 gdb 数据库中的文件呢?实际上很简单,在你知道数据库中的文件名称的前提下,同样也是可以通过输入地址获得文件。Chapter2/code2.py 文件的代码如下:# -*- coding:utf-8 -*-import arcpyimport oscws = os.getcwd()# 设置工作空间arcpy.env.workspace = cws# 可以覆盖同名文件arcpy.env.overwriteOutput = True# 导出数据库要素类 ▶注释1◀arcpy.CopyFeatures_management("../NYC.gdb/Boroughs", "out2.shp")# 将shp文件导入数据库 ▶注释2◀arcpy.CopyFeatures_management("../SHP/Boroughs.shp","../NYC.gdb/Boroughs2")可以看到在 ▶注释1◀ 处,直接输入数据库的名称 NYC.gdb,然后斜杠,然后要素类的名称。这样就可以读取数据库中的文件。同时也支持 shp 文件保存到 gdb 数据库中,可以看到 ▶注释2◀ 的代码将 SHP 文件夹中的 Boroughs.shp 文件保存到数据库 NYC.gdb 中。Note:如果你需要让计算机自动地查询数据库中的要素类名称的话,可以使用 arcpy.da.Walk,该方法类似于 os.walk,在其基础上扩展了对于 GDB 等地理空间数据库的支持。3.使用 Layer 类使用 arcpy.mapping 中的 Layer 类不仅可以读取 shp 格式的文件,还可以读取 .lyr 图层文件、gdb 数据库中的文件,甚至还可以读取 .dwg 为后缀的 CAD 工程文件。Chapter2/code3.py,使用 Layer 类的示例。# -*- coding:utf-8 -*-import arcpyimport oscws = os.getcwd()# 设置工作空间arcpy.env.workspace = cws# 可以覆盖同名文件arcpy.env.overwriteOutput = True# 使用Layer类shp_file = arcpy.mapping.Layer("../SHP/Boroughs.shp")arcpy.CopyFeatures_management(shp_file, "out3.shp")# ▶注释1◀shp_file2 = arcpy.mapping.Layer("../NYC.gdb/Boroughs")arcpy.mapping.Layer 类中直接输入 shp 文件的地址即可,如果想要读取 .lyr 后缀的图层文件的话也是输入地址即可。arcpy.mapping.Layer 类可以将单纯的地址字符串转换成真正的图层对象。在该示例代码中,shp_file 获取了arcpy.mapping.Layer 类的返回对象,变量 shp_file 就是 Boroughs.shp 文件的数据图层对象。▶注释1◀:使用 Layer 类直接获得 gdb 数据库中的要素类也是可以的。使用 Layer 类获取 cad 文件中的矢量文件对象,见代码 Chapter2/code4.pyimport arcpyimport osclass CAD2Shp(object):def __init__(self, cad):self.cad = cadself.convert()def convert(self):pt = arcpy.mapping.Layer(self.cad+"\Point")pl = arcpy.mapping.Layer(self.cad+"\Polyline")pg = arcpy.mapping.Layer(self.cad+"\Polygon")arcpy.CopyFeatures_management(pt, "pt.shp")arcpy.CopyFeatures_management(pl, "er")arcpy.CopyFeatures_management(pg, "pg")if __name__ == '__main__':arcpy.env.workspace = os.getcwd()arcpy.env.overwriteOutput = TrueCAD2Shp(u"设计图.dwg")code4.py 示例代码把文件 设计图.dwg 中的线要素、点要素、面要素导出为 shp 格式。设计图.dwg 这个文件由于某些原因我没有放到教程文件中,请注意一下,如果想要测试一下的话可以自己准备一个 dwg 文件。Note:如果你想 shp 格式转 dwg 格式的话可以使用 arcpy.ExportCAD_conversion 方法。4.读取栅格对象相关代码见 Chapter2/code7.py,注意是文件 code7.py 哦!# -*- coding:utf-8 -*-import arcpyimport oscws = os.getcwd()# 设置工作空间arcpy.env.workspace = cws# 可以覆盖同名文件arcpy.env.overwriteOutput = Trueraster_p = "../Raster/N31E107.tif"# ▶注释1◀new_raster = arcpy.sa.Slope(raster_p)# ▶注释2◀new_raster.save("../NYC.gdb/raster")new_raster.save("raster.tif")# ▶注释3◀raster_obj = arcpy.Raster(raster_p)arcpy.sa.Slope(raster_obj).save("raster2.tif")raster_p 是 dem 栅格文件的地址。▶注释1◀:arcpy.sa.Slope() 方法是可根据 dem 栅格数据判断栅格表面的各像元中的坡度,是一种使用非常广泛的空间分析方法。从这里可以看到,该方法中只传入了 dem 栅格地址,没有传入输出地址,这也是栅格数据与矢量数据在 ArcPy 中处理的一个不同之处。▶注释2◀:那么如何输出成果栅格呢?实际上该方法的返回值就是输出的坡度栅格,但仍然存在于系统中,使用 save() 方法可以保存到指定的磁盘位置上。当然不仅可以存放在文件夹中,也可以存放进 gdb 数据库。▶注释3◀:上面的 raster_p 仅仅是表示栅格数据文件的地址。尽管直接将其传入方法 arcpy.sa.Slope() 中没有问题,也成功输出了结果。但是!该程序方法在内部是将其装换成了栅格对象,然后再进行处理的。尽管很多栅格处理的方法都会在内部将栅格文件地址转换成栅格对象,但是有的不会,使用栅格代数计算的时候也不会,你需要使用 arcpy.Raster() 这个类来将栅格文件的地址字符串转换成栅格对象。并且我强烈建议,在面对栅格数据的时候,都自己手动将其转换成栅格对象。就像 ▶注释3◀ 一样!在 mxd 文件基础上处理数据
1.获得 mxd 文件对象1.1什么叫获得 mxd 文件?为什么放到前头讲?mxd 文件也叫地图文档文件,指以 .mxd 作为文件后缀的 ArcGIS Desktop 地图文档文件。在我们处理数据、读取数据过程中,纵然大部分时间都是绕过了 ArcGIS,包括 mxd 文件,但是仍然有可能会遇到处理 mxd 文件的情况,比如使用 Python(ArcPy)读取、替换、修改、导出 mxd 文件中的数据或者直接往 mxd 文件中添加数据。在 Python 语言中 mxd 文件会被转化成一个 mxd 文件对象。程序会把输入的 mxd 文件地址字符串转换成地图文档对象,我们只有根据这个地图文档对象才能一步步的接近 mxd 文件里面的数据,进而执行其他更深的操作。为了在 mxd 文件上处理数据,获得 mxd 文件对象是我们的第一步。arcpy 的 mapping 模块中提供 MapDocument(path) 函数,可以帮助我们获得 mxd 文件对象。下面的内容中会有一些获取 mxd 对象的操作,同时由于还存在着两种不同的 mxd 文件对象,所以更要把这个东西放到前面讲清楚。1.2两种 mxd 文件对象arcpy 不能直接创建 mxd 文件。所以如果需要对 mxd 文件进行操作的话,需要指定是当前的 mxd 文件还是指定已经存在的 mxd 文件。就是由于当前和已经存在这两种情况,两种识别 mxd 文件对象的方式有所区别。什么叫当前?在打开的 ArcMap 界面,从内置的 Python 窗口或者自定义的工具箱中运行代码,且运行的程序代码需要读取、修改位于该 ArcMap 中的图层文件,亦或者向其中添加图层文件时,就叫当前。在 ArcMap 主界面中,点击上方标准工具条上的这个标志 可以打开自带的 Python 窗口。使用 arcpy.mapping.MapDocument(path) 可以创建地图文档对象,用于访问地图文档中的属性和方法。path 参数是 mxd 文件的地址,字符串。在当前这种情况下,只能传入参数 "CURRENT",这样就能返回当前地图文档对象。import arcpymxd = arcpy.mapping.MapDocument("CURRENT")在 Python 窗口中输入代码并运行,见Chapter2/code5.py# -*- coding:utf-8 -*-import arcpy# mxd文档对象mxd = arcpy.mapping.MapDocument("CURRENT")# 数据框df = arcpy.mapping.ListDataFrames(mxd)[0]lyr_path = ur"G:\MoveOn\arcpyTutoraial\SHP\Boroughs.shp"lyr = arcpy.mapping.Layer(lyr_path)arcpy.mapping.AddLayer(df, lyr)# 刷新 arcmap 界面arcpy.RefreshTOC()arcpy.RefreshActiveView()你现在只需知道这个程序需要在 Python 窗口运行,然后它会将文件 Boroughs.shp 添加到当前 ArcMap 中。试着运行一下,将 Chapter2/code5.py 中的代码复制粘贴到 Python 窗口,然后按回车运行,结果如下图,成功将 shp 文件添加到当前 ArcMap 界面。
Note:使用"CURRENT"来获得当前地图文档对象的情况不多,并且大部分情况下,Python 窗口用于调试或者教学,少部分使用于个人编写的 arctoolbox 工具箱。毕竟你都使用 ArcPy 了,还打开 ArcGIS 干嘛啊?了解扩展:自从 ArcGIS 引入 Python 后,也在程序中内嵌了一个 Python 交互窗口。在Python 窗口中,可以高效、便捷、交互式地使用地理处理工具和 ArcGIS 中的 Python 函数。可在该窗口中运行的 Python 命令包括单行代码,也包括带逻辑的复杂块。在 Python 窗口中,还可通过自定义或第三方 Python 模块和库来实现其他功能。Python 窗口,是具有交互功能的,你可以在同一个窗口多次执行 Python 代码,并且交互窗口能够保存你之前执行代码产生的结果以及设定好的全局变量等参数。不同于一般情况在代码运行完后程序自动结束。在 Python 交互窗口中不会立即结束程序,它保存结果和参数,等待下一次输入代码片段并执行。并且当运行 Python 代码报错时,Python 交互窗口也不会退出,之前保存的结果和参数也不会丢失,可以放心使用。
位于 ArcMap 主界面右边的是 ArcToolBox 工具箱,也是整个 ArcGIS 最核心的功能,不仅有丰富强大的功能,还有不错的扩展性,开发者可以将自己写的 Python 代码在这里封装成工具箱。和 Python 窗口一样,可以使用 "CURRENT" 字符串来获得当前 mxd文件的对象。更详细内容先按下不表,因为工具箱相关内容较多较杂,之后有单独篇章详细说明。什么叫已经存在?和上面的当前相对应的是已经存在,已经存在使用的更加广泛一些。在这里我们不再通过传入 "CURRENT" 参数来获取地图文档对象,而是使用具体的 mxd 文件的地址。import arcpymxd = arcpy.mapping.MapDocument("chapter2MXD.mxd")在这种情况下基本上就不使用 ArcGIS 自带的 Python 窗口。直接使用 PyCharm 编写、调试、运行代码,关于如何几分钟内安装和配置好 PyCharm 可以查看该系列的第一章。在 PyCharm 运行以下代码,代码可见于文件 Chapter2/code6.py。import arcpyarcpy.env.overwriteOutput = True# mxd文档对象mxd = arcpy.mapping.MapDocument("chapter2MXD.mxd")# 数据框 ▶注释1◀df = arcpy.mapping.ListDataFrames(mxd)[0]# ▶注释2◀print "DataFrame Scale:{}".format(df.scale)print "DataFrame Extent:{}".format(df.extent)print "DataFrame Type:{}".format(df.type)# ▶注释3◀exist_lyr = arcpy.mapping.ListLayers(mxd)[0]print exist_lyr.name# 添加shp到mxd ▶注释4◀lyr_path = ur"../SHP/Boroughs.shp"lyr = arcpy.mapping.Layer(lyr_path)arcpy.mapping.AddLayer(df, lyr)# 添加栅格数据 ▶注释5◀raster_p = "../Raster/N31E107.tif"raster_lyr = arcpy.mapping.Layer(raster_p)arcpy.mapping.AddLayer(df, raster_lyr)# ▶注释6◀mxd.saveACopy("output.mxd", version="10.1")运行后,你可以见到一个新创建的 mxd 文件:output.mxd。运行成功,一切都非常良好(具体情况说明紧接下面)。这些区别终于讲完了,总的来说,当前和已经完成的区别就是应用 mxd 的状态不同,一个是针对当前的,一个是针对已经保存好了的,在语法上的区别就是 "CURRENT"。后者的实际应用更多。2.MXD 数据操作(温馨提示,如果头晕的话,再去看看最上面的目录和流程表!)讲完了区别,现在讲讲操作的共同点。共同点从何而来?因为上面两种形式都应用于 mxd 文件上,这就是共同点。继续使用上面最新的示例,Chapter2/code6.py:import arcpyarcpy.env.overwriteOutput = True# mxd文档对象mxd = arcpy.mapping.MapDocument("chapter2MXD.mxd")# 数据框 ▶注释1◀df = arcpy.mapping.ListDataFrames(mxd)[0]# ▶注释2◀print "DataFrame Scale:{}".format(df.scale)print "DataFrame Extent:{}".format(df.extent)print "DataFrame Type:{}".format(df.type)# ▶注释3◀exist_lyr = arcpy.mapping.ListLayers(mxd)[0]print exist_lyr.name# 添加shp到mxd ▶注释4◀lyr_path = ur"../SHP/Boroughs.shp"lyr = arcpy.mapping.Layer(lyr_path)arcpy.mapping.AddLayer(df, lyr)# 添加栅格数据 ▶注释5◀raster_p = "../Raster/N31E107.tif"raster_lyr = arcpy.mapping.Layer(raster_p)arcpy.mapping.AddLayer(df, raster_lyr)# ▶注释6◀mxd.saveACopy("output.mxd", version="10.1")既然获得了 mxd 对象,下面就是一步一步深入,想剥洋葱一样将其中的属性、信息都读取出来。获得数据框 ▶注释1◀&▶注释2◀:mxd 之下首先就是数据框,下面这个叫“图层”的实际就是一个数据框,一个 mxd 可以创建多个数据框;图层文件必须依附于一个数据框,就像下面的 FireCompanies 图层。
arcpy.mapping.ListDataFrames(),需要传入 mxd 对象,还支持传入通配符。返回的是包含数据框对象的列表,注意哦,是列表,就算只有一个数据框返回的也是列表,所以我在后面加上了 [0],将数据框对象取了出来。从 ▶注释2◀ 可以看到,返回的数据框对象也包含了不少属性和方法。获取图层 ▶注释3◀:使用 arcpy.mapping.ListLayers() 可以获取 mxd 文件中已经存在的各种图层对象,包括矢量和栅格。和上面获得数据框对象的方法一样,返回的也是列表,需注意。添加图层 ▶注释4◀ & ▶注释5◀:添加图层就不能直接输入 shp 文件的地址,包括 gdb 数据库中的要素类。只有要素图层(FeatureLayer)才能添加到 mxd 文件中,而不是要素类(FeatureClass)。关于要素图层和要素类现在不用太在意,只需知道这个概念就好。所以我们需要使用 arcpy.mapping.Layer 这个方法将要素类变成要素图层,然后使用 AddLayer 方法即可将该要素图层添加到指定的数据框中(InsertLayer 和 AddLayer 方法类似)。使用 Layer 类也可以添加栅格数据, 操作同添加矢量,见 ▶注释5◀。另存 mxd 后,打开该地图文档,可以看到内容列表中的图层数量从一个变成了三个。添加了一个要素图层、一个栅格图层。
保存/另存 ▶注释6◀:使用 save() 可以保存修改过的 mxd 文件。使用 saveACopy() 是另存,可以指定另存文件名称以及另存的版本。其他:替换图层。使用 arcpy.mapping.UpdateLayer 方法,该方法非常强大,不仅可以直接更换图层,还可以用于更新图层的样式。关于使用 UpdateLayer 更换样式可以查看这篇文章;移除图层。arcpy.mapping.RemoveLayer() 方法用于移除 mxd 文件中的图层。移动图层。使用 arcpy.mapping.MoveLayer() 方法可以移动图层(限制太大没什么用)。Note:以上的很多方法和类只是简单展示一下,主要是帮助大家指明方向,更多的细节各位读者可以翻阅官方文档。创建数据列表
我们再看一眼开头的结构图。
可以看到最左边的创建数据列表框上写着“通用”,这是什么意思呢,表示当前讲的这一节与先前是否独立、是否涉及 mxd 文件都没有必要的联系,是大家都可以使用的方法,也比较简单。创建数据列表主要涉及 ArcPy 中这几个函数:ListFiles(wild_card) 返回工作空间中的所有文件的列表;ListRasters(wild_card, raster_type) 返回工作空间中的栅格文件的列表;ListTables(wild_card, table_type) 返回工作空间中表的列表;ListDatasets(wild_card, feature_type) 返回工作空间中数据集的列表;ListFeatureClasses(wild_card, feature_type, feature_dataset) 返回工作空间中矢量文件的列表。wild_card 表示通配符,这些函数可以直接搜寻工作空间中有没有相应类型以及与通配符相匹配的文件,然后以列表的形式返回。使用这些方法可以不再使用文件后缀去筛选矢量文件了。其中使用最多就是 ListFeatureClasses 和 ListRasters以下示例见文件 Chapter2/code8.py# -*- coding:utf-8 -*-import arcpy# ▶注释1◀arcpy.env.workspace = "../SHP"fcs = arcpy.ListFeatureClasses()for fc in fcs:print fc# ▶注释2◀arcpy.env.workspace = "../NYC.gdb"fcs = arcpy.ListFeatureClasses("*Water*")for fc in fcs:print fc▶注释1◀:以 ../SHP 文件夹作为工作空间。然后返回矢量文件名称列表。▶注释2◀:以 ../NYC.gdb 数据库作为工作空间,使用通配符 *Water* 去匹配文件名称带有 Water 的文件,不管 Water 这个单词在开头、中间、还是结尾。以上。结束语
该章节内容比较简单,但是又存在不同的情况,所以这里把所有情况整理记录下来。如果读者以后有遇到相关问题,可以再来细细的查阅。使用版本:Windows 10PyCharm 2020.3.3ArcGIS 10.3Python2.7源代码、教学文档离线小册子下载: