一、内容提示
通过解析mdb地理数据库,获取了图层之间的组织结构、空间参考、表字段属性等信息。
下一步,就是将数据输出到GDB中。
下面详细介绍python3.9版本,读写GDB数据的方法:
(1)使用ArcPy创建GDB、读写GDB;
(2)使用osgeo创建、读写GDB;
(3)使用fiona、geopandas创建、读写GDB;
(4)将osgeo或geopandas模块添加到自定义模块,实现其与ArcGIS环境的共存
MDB转出为GDB,涉及的内容比较多,尤其是需要开源实现。每一篇文章的内容篇幅都很长,希望对大家有帮助。
(1)mdb(个人地理数据库)转shape file其实并不简单
(2)mdb转gdb实现过程介绍(1)mdb地理数据库结构解析和gdb库的创建
二、FileGDB驱动
GDB是Esri开发的一种地理数据库格式,它旨在存储和管理地理空间数据。GDB可以包含矢量数据、栅格数据、拓扑数据、地图符号化信息以及数据集之间的关联关系等。
GDB作为Esri的一种地理数据库格式,并非完全开源,它提供了开放式的文件规范和API,在一定程度上允许与其他软件集成和交互。
在以往(python<3.9),都是通过配置FileGDB驱动,实现对GDB数据的读写。
在使用习惯上,一般有两种办法:
(1)通过安装GDAL的方式添加FileGDB驱动
一般是通过osgeo中的ogr实现GDB文件的读写,需要拷贝FileGDBAPI.dll至python安装目录下的“\Lib\site-packages\osgeo”;
FileGDBAPI.dll下载地址:
https://github.com/Esri/file-geodatabase-api
GDAL的whl文件下载地址:
https://github.com/cgohlke/geospatial-wheels/releases
GDAL 3.x 版本,还需要把gdalplugins\disabled中的ogr_FileGDB.dll移动到gdalplugins目录;
GDAL 2.x版本,修改osgeo/__init__.py文件:注释15行,取消注释17行,如下:
# __init__ for osgeo package.
# unofficial Windows binaries: set GDAL environment variables if necessary
import os
try:
_here = os.path.dirname(__file__)
if _here not in os.environ['PATH']:
os.environ['PATH'] = _here + ';' + os.environ['PATH']
if 'GDAL_DATA' not in os.environ:
os.environ['GDAL_DATA'] = os.path.join(_here, 'data', 'gdal')
if 'PROJ_LIB' not in os.environ:
os.environ['PROJ_LIB'] = os.path.join(_here, 'data', 'proj')
if 'GDAL_DRIVER_PATH' not in os.environ:
#pass
# uncomment the next line to enable plugins
os.environ['GDAL_DRIVER_PATH'] = os.path.join(_here, 'gdalplugins')
except Exception:
pass
del os
(2)使用'fiona'引擎实现,一般是通过geopandas完成GDB文件的读写
为了方便介绍,假设利用conda新建一个geopandas的虚拟环境,复制FileGDBAPI.dll文件,粘贴到利用conda新建的虚拟环境根目录下的Library\bin里。然后将ogr_FileGDB.dll这个文件放置于前面FileGDBAPI.dll同级目录下的gdalplugins目录中即可。
三、OpenFileGDB驱动
前文对python的版本进行了高亮,这个版本的分水岭是3.9,现在对这个版本分界的原因做一个简单的说明。
在python3.9版本,用前文的方法配置FileGDB驱动已经行不通了,而小编也尝试了多种方法,并没有成功。有成功配置FileGDB驱动的小伙伴,望指导。
于是,我将方向转为配置OpenFileGDB驱动。
关于FileGDB驱动与OpenFileGDB驱动的详细介绍,可以通过GDAL社区文档获的相关信息。文档地址为:https://gdal.org/
(1)FileGDB驱动
-
FileGDB驱动是用于ArcGIS File Geodatabase(FileGDB)格式的驱动程序,允许在GDAL/OGR库中读取和写入FileGDB数据。
-
这个驱动是专门为ArcGIS FileGDB格式设计的,是Esri提供的官方支持。
(2) OpenFileGDB驱动
-
OpenFileGDB驱动也是用于ArcGIS File Geodatabase(FileGDB)格式的驱动程序,但是它是GDAL/OGR库的一部分,提供了对FileGDB格式的开源支持。
-
OpenFileGDB驱动允许在GDAL/OGR库中使用FileGDB数据,无需依赖ArcGIS软件。
在python3.9版本之前,安装的fiona包含了'OpenFileGDB'驱动,OpenFileGDB就是gdal中默认自带的针对gdb文件的驱动,但其对应的值为'r',说明它只能针对gdb文件进行读取。
ArcGIS Pro 3.1版本,使用的Python版本是3.9.16。克隆的python环境,在安装了fiona后,惊奇的发现,其对OpenFileGDB的支持,已经是“raw”。
但是,现实总是残酷的。要想通过fiona实现对gdb数据的写入,需要gdal的版本在3.6.0以上,而当前gdal的版本为3.4.0。报错信息如下:
因此,现在的目标转为升级gdal版本到3.6.0以上。这时候,需要考虑的因素为:
- 若脚本需要封装为python工具箱,直接使用Pro的python环境或基于Pro克隆的python环境,是不让升级gdal版本的;(得另想办法)
- 若脚本后续不会使用到arcgis或arcpy模块,则直接安装3.6.0及以上的gdal版本即可;
四、3种GDB的创建、读写方法
4.1 ArcPy 创建、读写GDB数据
使用ArcPy可以轻松地创建、读取和写入Geodatabase(GDB)数据。下面分别介绍如何创建GDB数据和如何读取/写入GDB数据,并附上示意代码。
(1)创建GDB数据
要创建GDB数据,可以使用CreateFileGDB_management
函数。
import arcpy
# 设置工作空间
arcpy.env.workspace = r"C:\path\to\your\workspace"
# 定义GDB名称和保存路径
gdb_name = "MyGDB.gdb"
gdb_path = arcpy.env.workspace
# 创建GDB
arcpy.CreateFileGDB_management(gdb_path, gdb_name)
(2)读取GDB数据
要读取GDB数据,可以使用ListFeatureClasses和ListTables函数来列出GDB中的要素类和表。
import arcpy
# 设置工作空间
arcpy.env.workspace = r"C:\path\to\your\workspace\MyGDB.gdb"
# 获取要素类列表
feature_classes = arcpy.ListFeatureClasses()
# 获取表列表
tables = arcpy.ListTables()
# 打印要素类和表名
print("Feature Classes:")
for fc in feature_classes:
print(fc)
print("\nTables:")
for table in tables:
print(table)
(3)写入GDB数据
要写入GDB数据,可以使用相应的InsertCursor来插入新的要素或记录到要素类或表中。
import arcpy
# 设置工作空间
arcpy.env.workspace = r"C:\path\to\your\workspace\MyGDB.gdb"
# 要素类路径
fc_path = "MyFeatureClass"
# 字段列表
fields = ["Field1", "Field2"]
# 创建InsertCursor
with arcpy.da.InsertCursor(fc_path, fields) as cursor:
# 插入新要素
cursor.insertRow(("Value1", "Value2"))
4.2 osgeo 创建、读写GDB数据
安装gdal,使用osgeo的ogr实现GDB的创建、读写。
步骤:
- 在python3.9版本中安装gdal3.8.4;
- 使用org创建、读写GDB数据;
(1)安装GDAL3.8.4
为了便于后续osgeo及其依赖迁移到自定义模块中,使用conda新建一个虚机环境。
01 在python3.9中安装gdal
#在conda默认envs目录下创建虚拟环境osgeo-write-gdb-test
conda create -n osgeo-write-gdb-test python=3.9 -c https://mirrors.sjtug.sjtu.edu.cn/anaconda/pkgs/main -y
#conda在指定目录下创建虚拟环境osgeo-write-gdb-test
conda create --prefix C:\ProgramData\Miniconda3\envs\osgeo-write-gdb-test python=3.9.16
下载GDAL-3.8.4-cp39-cp39-win_amd64.whl,我们知道,https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml网站已经打不开了,而GDAL在CSDN上下载,又需要会员或积分,需要GDAL的,可到https://github.com/cgohlke/geospatial-wheels/releases中下载。
安装gdal:GDAL-3.8.4-cp39-cp39-win_amd64.whl
pip install GDAL-3.8.4-cp39-cp39-win_amd64.whl
(2) osgeo创建、读写gdb
在解释器osgeo-write-gdb-test下,新建GDB和图层。
from osgeo import ogr, osr, gdal
# 设置新的GDB文件路径
gdb_file_path = './new_demo.gdb'
# 创建数据驱动
driver = ogr.GetDriverByName("OpenFileGDB")
data_source = driver.CreateDataSource(gdb_file_path)
if data_source is not None:
print("Successfully created GDB:", gdb_file_path)
else:
print("Failed to create GDB:", gdb_file_path)
# 获取并打印 GDAL 的版本信息
print("GDAL Version:", gdal.__version__)
# 创建数据驱动
driver = ogr.GetDriverByName("OpenFileGDB")
data_source = driver.Open(gdb_file_path, 1) # 1 表示以写入模式打开数据源,如果数据源不存在则创建新的
# 创建坐标系和图层
if data_source is not None:
srs = osr.SpatialReference()
srs.ImportFromEPSG(4490) # 你所需的 EPSG 编码
outLayer = data_source.CreateLayer("ds", srs=srs, geom_type=ogr.wkbPolygon) # 创建图层
if outLayer is None:
print("Layer creation failed!")
else:
print("OpenFileGDB driver is not available.")
上述代码,在当前目录创建一个名为“new_demo”的gdb,并在该gdb中新建一个图层“ds”,执行结果如下:
4.3 fiona、geopandas 创建、读写GDB数据
安装geopandas,分别使用geopandas和fiona实现GDB的创建、读写。
步骤:
- 在python3.9版本中安装geopandas;
- 创建、读写GDB数据;
(1) 安装geopandas
为了便于后续geopandas及其依赖迁移到自定义模块中,使用conda新建一个虚机环境。
01 在python3.9中安装geopandas
#在conda默认envs目录下创建虚拟环境geopandas-write-gdb-test
conda create -n geopandas-write-gdb-test python=3.9 -c https://mirrors.sjtug.sjtu.edu.cn/anaconda/pkgs/main -y
#conda在指定目录下创建虚拟环境geopandas-write-gdb-test
conda create --prefix C:\ProgramData\Miniconda3\envs\geopandas-write-gdb-test python=3.9.16
#安装geopandas
conda install geopandas -c https://mirrors.sjtug.sjtu.edu.cn/anaconda/cloud/conda-forge -y
(2) 创建、读写GDB数据
01 使用geopandas创建、读写gdb
在解释器geopandas-write-gdb-test下,新建GDB和图层。
import geopandas as gpd
from shapely.geometry import Point, LineString, Polygon
demo_point_layer = gpd.GeoDataFrame(
{
'数据字段测试': ['点要素测试数据字段测试'],
'geometry': [Point(0, 0)]
},
crs='EPSG:4326'
)
demo_linestring_layer = gpd.GeoDataFrame(
{
'数据字段测试': ['线要素测试数据字段测试'],
'geometry': [LineString([(0, 0), (1, 1)])]
},
crs='EPSG:4326'
)
demo_polygon_layer = gpd.GeoDataFrame(
{
'数据字段测试': ['面要素测试数据字段测试'],
'geometry': [Polygon([(0, 0), (1, 1), (1, 0)])]
},
crs='EPSG:4326'
)
# 写出到示例gdb文件中
demo_point_layer.to_file('./demo1.gdb', layer='点图层测试', driver='OpenFileGDB')
demo_linestring_layer.to_file('./demo1.gdb', layer='线图层测试', driver='OpenFileGDB')
demo_polygon_layer.to_file('./demo1.gdb', layer='面图层测试', driver='OpenFileGDB')
上述代码,在当前目录创建一个名为“demo1”的gdb,并在该gdb中新建一个图层三个图层,执行结果如下:
02 使用fiona创建、读写gdb
import fiona
# 创建示例数据
demo_polygon = {
'type': 'Polygon',
'coordinates': [[(0, 0), (1, 1), (1, 0), (0, 0)]]
}
# 设置文件路径
gdb_file = './demo2.gdb'
# 将投影数据文件添加到环境变量中
# import os
# os.environ["PROJ_LIB"] = "C:/proj"
# 创建GDB文件和图层
with fiona.open(gdb_file, 'w', driver='OpenFileGDB', crs='EPSG:4326', layer='polygon_layer', schema={'geometry': 'Polygon', 'properties': {}}) as layer:
layer.write({'geometry': demo_polygon, 'properties': {}})
# 读取GDB数据
with fiona.open(gdb_file, 'r', driver='OpenFileGDB') as layer:
for feature in layer:
print(feature)
执行上述代码,会报错“fiona.errors.CRSError: The WKT could not be parsed. PROJ: proj_create_from_database: Cannot find proj.db”,如下所示:
这个错误是fiona缺失投影数据的定义文件(通常是 proj 文件)引起的。可通过将proj文件夹添加到环境变量中解决。
注意:
- 通过直接安装geopandas,不能获得proj 文件。需要安装GDAL后,在‘\Lib\site-packages\osgeo\data\proj’处获得,可在代码执行中自动将其添加到环境变量中解决;
- os.environ["PROJ_LIB"] 添加的proj路径,不能包含中文;
import os
os.environ["PROJ_LIB"] = "C:/proj"
生成的gdb如下:
五、osgeo、fiona、geopandas 开源读、写gdb,如何与Arcpy环境共存?
前面我们通过开源的方式实现了对GDB的创建和读写,但是都是在原生安装GDAL和Geopandas的虚机环境中。
如果我们需要调用arcpy或arcgis模块,或后期将脚本封装为工具,就需要将实现gdb读、写实现的模块放到自定义模块中,并实现其与ArcGIS环境的共存。
步骤:
(1)创建自定义模块,将开源读写gdb的模块置于其中;
(2)使用ogr创建gdb,并使用arcpy获取图层列表;
(3)使用fiona创建gdb,并使用arcpy获取图层列表;
(4)使用geopandas创建gdb,并使用arcpy获取图层列表。
5.1 将开源实现读、写gdb,组织到自定义模块中
这部分非常重要。我们知道,ArcGIS Pro的python环境是不允许我们添加包的,而我们为了添加包,就需要克隆python环境,再在克隆环境中添加包。但是我们会碰到非常尴尬的两个问题:
(1)安装的包可能与克隆环境内的包版本冲突,导致无法正常安装或后续莫名其妙的错误;
(2)当我们基于Pro自定义python工具箱后,那些我们定义的工具,可能在克隆环境中添加了第三方包,这在部署和推广使用时,带来了很大的不便。
01 将gdal添加到自定义模块
我们在通过conda创建的虚拟环境osgeo-write-gdb-test中,安装GDAL-3.8.4-cp39-cp39-win_amd64.whl,在site-packages文件夹下,能看到我们已经安装的包或模块。如下图:
我们将上图中绿框中的三个文件夹,拷贝至我们自定义的文件夹“myosgeo”中,并在myosgeo文件夹下创建__init__.py。如下图:
在__init__.py文件夹中添加如下代码:
import os
import sys
# 获取当前模块所在目录的路径
module_dir = os.path.dirname(__file__)
# 将当前模块所在目录添加到sys.path中
sys.path.insert(0, module_dir)
02 将geopandas添加到自定义模块
import os
import sys
# 获取当前模块所在目录的路径
module_dir = os.path.dirname(__file__)
# 将当前模块所在目录添加到sys.path中
sys.path.insert(0, module_dir)
03 将geopandas添加到自定义模块
我们在通过conda创建的虚拟环境geopandas-write-gdb-test中,site-packages文件夹下,将geopandas及其依赖的模块拷贝到“myenv"文件夹中,并添加__init__.py,__init__.py内的内容相同。
拷贝的内容如下:
5.2 使用自定义模块中的ogr创建gdb,使用arcpy读取gdb
测试示例代码如下:
from mygeos.osgeo import ogr, osr, gdal
import arcpy
# 设置新的GDB文件路径
gdb_file_path = './new_demo_arcpy.gdb'
# 创建数据驱动
driver = ogr.GetDriverByName("OpenFileGDB")
data_source = driver.CreateDataSource(gdb_file_path)
if data_source is not None:
print("Successfully created GDB:", gdb_file_path)
else:
print("Failed to create GDB:", gdb_file_path)
# 获取并打印 GDAL 的版本信息
print("GDAL Version:", gdal.__version__)
# 创建数据驱动
driver = ogr.GetDriverByName("OpenFileGDB")
data_source = driver.Open(gdb_file_path, 1) # 1 表示以写入模式打开数据源,如果数据源不存在则创建新的
# 创建坐标系和图层
if data_source is not None:
srs = osr.SpatialReference()
srs.ImportFromEPSG(4490) # 你所需的 EPSG 编码
outLayer = data_source.CreateLayer("使用自定义ogr创建的测试图层", srs=srs, geom_type=ogr.wkbPolygon) # 创建图层
if outLayer is None:
print("Layer creation failed!")
else:
print("OpenFileGDB driver is not available.")
data_source = None
arcpy.env.workspace = gdb_file_path
print(arcpy.ListFeatureClasses())
输出如下:
5.3 使用自定义模块中的geopandas创建gdb,使用arcpy读取gdb
测试示例代码如下:
# -*-coding:utf-8-*-
import arcpy
from myenv import geopandas as gpd
from myenv.shapely.geometry import Point, LineString, Polygon
demo_point_layer = gpd.GeoDataFrame(
{
'数据字段测试': ['点要素测试数据字段测试'],
'geometry': [Point(0, 0)]
},
crs='EPSG:4326'
)
demo_linestring_layer = gpd.GeoDataFrame(
{
'数据字段测试': ['线要素测试数据字段测试'],
'geometry': [LineString([(0, 0), (1, 1)])]
},
crs='EPSG:4326'
)
demo_polygon_layer = gpd.GeoDataFrame(
{
'数据字段测试': ['面要素测试数据字段测试'],
'geometry': [Polygon([(0, 0), (1, 1), (1, 0)])]
},
crs='EPSG:4326'
)
# 写出到示例gdb文件中
demo_point_layer.to_file('./demo_geopandas.gdb', layer='gdf点图层自定义模块测试', driver='OpenFileGDB')
demo_linestring_layer.to_file('./demo_geopandas.gdb', layer='gdf线图层自定义模块测试', driver='OpenFileGDB')
demo_polygon_layer.to_file('./demo_geopandas.gdb', layer='gdf面图层自定义模块测试', driver='OpenFileGDB')
data_source = None
arcpy.env.workspace = './demo_geopandas.gdb'
print(arcpy.ListFeatureClasses())
输出如下:
5.4 使用自定义模块中的fiona创建gdb,使用arcpy读取gdb
测试示例代码如下:
from myenv import fiona
import arcpy
# 创建示例数据
demo_polygon = {
'type': 'Polygon',
'coordinates': [[(0, 0), (1, 1), (1, 0), (0, 0)]]
}
# 设置文件路径
gdb_file = './demo_fiona.gdb'
import os
os.environ["PROJ_LIB"] = "C:/proj"
# 创建GDB文件和图层
with fiona.open(gdb_file, 'w', driver='OpenFileGDB', crs='EPSG:4326', layer='fiona开源自定义模块测试', schema={'geometry': 'Polygon', 'properties': {}}) as layer:
layer.write({'geometry': demo_polygon, 'properties': {}})
# 读取GDB数据
with fiona.open(gdb_file, 'r', driver='OpenFileGDB') as layer:
for feature in layer:
print(feature)
data_source = None
arcpy.env.workspace = './demo_fiona.gdb'
print(arcpy.ListFeatureClasses())
输出如下: