简介这是一份面向ArcGIS初级与中级用户的ArcPy数据转换实战资料核心解决个人地理数据库(.mdb)批量转换为文件地理数据库(.gdb)的自动化需求。文档以可运行的完整脚本为主线逐步拆解创建GDB、设置工作空间、使用ListFeatureClasses和ListTables遍历数据、通过FeatureClassToGeodatabase与TableToGeodatabase执行迁移等关键环节并附带逐段代码说明、函数作用解析及转换前后数据库差异讲解。资源为单个docx文档约12KB内容精炼打开即可对照学习。已有192人学习下载适合正在学习ArcPy自动化或承担数据迁移任务的GIS从业者。通过本例读者能掌握用脚本快速批量迁移地理数据的方法理解arcpy环境变量与地理处理工具配合使用的思路并学会在自动化流程中添加进度输出与错误处理避免重复手工操作。1. mdb 转 gdb 到底在解决什么问题不止是换了个格式mdb 转 gdb说白了就是把 Access 底层的个人地理数据库整体搬迁到文件地理数据库里。之前我处理过一批历史数据三五百个 mdb 散在七八个目录里ArcMap 老版本建的里面要素类、表、数据集交错嵌套手工用转换工具一个个转一周都转不完还容易漏。这套活儿的正经解法就是用 arcpy 写脚本批量跑把「打开 mdb → 选数据 → 转格式 → 落盘」这些动作全部交给代码让机器按目录自动扫、自动转、自动写日志人只需要处理失败项。这篇文章写给两类人数据管理员要整目录搬迁历史 mdb或者开发者要把转换流程嵌入到数据入库的自动化链路里。如果你也有几十个 mdb 躺在服务器上等处理这篇文章就是照做就能用的那种。2. 为什么选 arcpy 做自动执行三种方案对比与选型理由2.1 mdb 和 gdb 的本质差异容量、并发与稳定性先说说为什么要换。mdb 个人地理数据库底层是 Access 文件官方标注的单库容量上限约 2GB数据一多就报「空间不足」或者干脆打不开而且它是单用户写入机制多人同时编辑会出现锁冲突甚至文件损坏。gdb 文件地理数据库是文件夹形态存储单表数据量可以到 TB 级支持多个进程并发读崩溃恢复机制也成熟得多。另外新版本桌面软件很多高级功能——拓扑规则、网络数据集、附件、关系类——只对 gdb 完整开放mdb 只能当旧数据仓库存着功能扩展基本没戏。这两者不是单纯换个后缀内部的地物存储方式、字段类型映射、空间索引机制都不同。也正因如此转换不是把文件改个名就行必须走工具或脚本让底层结构真正重建一遍。手动转换短平快但面对几十上百个 mdb 时就不现实了。2.2 三条路线对比工具箱、ModelBuilder 与 arcpy 脚本实现 mdb 转 gdb业内常见的做法有三条方案操作方式适合场景主要缺点ArcToolbox 转换工具Feature Class to Geodatabase / Table to Geodatabase界面里选输入输出一次转几个文件无法批量、无法处理嵌套数据集ModelBuilder 模型拖拽工具连线把流程固化流程固定、希望给别人点按钮就用遍历文件系统能力弱循环逻辑难写arcpy 脚本Python 代码控制 arcpy 接口批量、定时、自动化、可排错需要会写 Python存在环境兼容问题我的判断很简单如果转换只是一次性、几个 mdb直接用工具箱拖参数就好如果这个流程要跑很多遍、或者要纳入数据更新流程就必须上 arcpy。脚本能把「扫描目录、判断是否已转换、记录日志、失败重试」这类逻辑都包进去这是 ModelBuilder 很难做好的。2.3 环境注意arcpy 不是 pip 装出来的这里要提醒一个新手常踩的坑arcpy 不是pip install arcpy能装的库它依赖桌面软件的授权环境。ArcMap 自带的是 Python 2.7 arcpyArcGIS Pro 自带 Python 3 arcpy。写脚本前先确认跑在哪个环境里否则代码语法、中文编码处理方式完全不一样。我现在一般直接用 Pro 环境Python 3 的编码处理比 2.7 省心太多路径也不用加u前缀。3. 第一个「mdb 转 gdb」脚本核心 API 与最小可用代码3.1 认识两个核心工具要素类转换与表转换arcpy 里做这件事的主角有两个FeatureClassToGeodatabase_conversion负责要素类点线面TableToGeodatabase_conversion负责属性表。这两个工具接受 mdb 里的数据对象名或路径作为输入输出到目标 gdb自动保留原有名称和字段结构。如果 mdb 里只有独立要素类和表没有要素数据集那这个最小脚本就能直接跑通# -*- coding: utf-8 -*- import arcpy # 输入 mdb 路径与输出 gdb 路径 input_mdb rD:\data\old_data.mdb output_gdb rD:\data\new_data.gdb # 设置当前工作空间为 mdbList 系列函数才能读到它内部的对象 arcpy.env.workspace input_mdb # 列出 mdb 根目录下的所有要素类不含要素数据集内的 feature_classes arcpy.ListFeatureClasses() for fc in feature_classes: arcpy.FeatureClassToGeodatabase_conversion(fc, output_gdb) print(f已转换要素类: {fc}) # 列出所有独立表 tables arcpy.ListTables() for table in tables: arcpy.TableToGeodatabase_conversion(table, output_gdb) print(f已转换表: {table})这个脚本的逻辑分三层设置环境工作空间、用 List 函数枚举数据对象、循环调用转换工具。arcpy.env.workspace是 arcpy 的全局环境变量设置后 List 系列函数会在这个空间下扫描不用写全路径。arcpy.FeatureClassToGeodatabase_conversion的第一个参数既可以是单个名称也可以是名称列表列表形式适合一次传多个要素类。第二个参数output_gdb如果不存在工具会自动帮我们创建。3.2 参数与边界为什么说这个脚本「不够用」上面这个脚本有一个隐患ListFeatureClasses()不会递归要素数据集内部。如果 mdb 里建了要素数据集Feature Dataset数据集内部的要素类不会被扫描到直接漏转。处理这种嵌套结构的常见做法是先用ListDatasets扫出数据集再切 workspace 到数据集内部去列出要素类。完整写法是这样# -*- coding: utf-8 -*- import arcpy import os input_mdb rD:\data\old_data.mdb output_gdb rD:\data\new_data.gdb arcpy.env.workspace input_mdb # 允许覆盖输出避免脚本重复跑时因为同名报错 arcpy.env.overwriteOutput True # 第一步处理所有要素数据集内部的数据 datasets arcpy.ListDatasets(, Feature) for ds in datasets: # 拼出数据集在 mdb 中的完整路径 ds_full os.path.join(input_mdb, ds) # 在目标 gdb 里创建同名数据集如果不存在 ds_out os.path.join(output_gdb, ds) if not arcpy.Exists(ds_out): arcpy.CreateFeatureDataset_management(output_gdb, ds) # 切 workspace 到该数据集内列出其中的要素类 arcpy.env.workspace ds_full for fc in arcpy.ListFeatureClasses(): arcpy.FeatureClassToGeodatabase_conversion(fc, ds_out) # 第二步把 workspace 切回 mdb 根处理独立要素类和表 arcpy.env.workspace input_mdb for fc in arcpy.ListFeatureClasses(): arcpy.FeatureClassToGeodatabase_conversion(fc, output_gdb) for table in arcpy.ListTables(): arcpy.TableToGeodatabase_conversion(table, output_gdb) print(转换完成)这里的关键在于arcpy.env.workspace是动态切换的。第一次切到数据集内部扫描第二次切回 mdb 根目录扫独立对象顺序不能反。用arcpy.Exists判断目标数据集是否已存在是为了让脚本可以重复执行而不报错。overwriteOutput True解决的是同名要素类重复转换时的覆盖问题——这条不设第二次跑大概率直接 999999 报错。4. 批量转换目录遍历、断点续传与完整脚本4.1 从一个 mdb 到整目录遍历逻辑与配置设计单个 mdb 的脚本能跑通之后批量化的核心就变成「谁来发现 mdb、谁来记录进度」。我用的是 Python 标准库os.walk递归扫目录找到所有.mdb后缀文件每个 mdb 对应生成一个同名 gdb转换前先检查该 gdb 是否已经转换过用标记文件接续上次的活。标记文件逻辑是我从数据迁移项目里保留的习惯每个 gdb 转完后在输出目录写一个空的.done文件。下次跑脚本时先查这个文件存在就直接跳过。这样哪怕半夜跑挂了第二天把脚本再跑一遍只会补转失败的几个不用全量重来。# -*- coding: utf-8 -*- import os import arcpy import traceback # 配置区 root_dir rD:\project\mdb_files # mdb 所在根目录 output_root rD:\project\gdb_output # 输出 gdb 所在目录 log_file os.path.join(output_root, convert_log.txt) # if not os.path.exists(output_root): os.makedirs(output_root) def write_log(msg): 写日志到文件并打印方便实时看进度 with open(log_file, a, encodingutf-8) as f: f.write(msg \n) print(msg) def convert_mdb(mdb_path, gdb_path): 把单个 mdb 完整转换为 gdb write_log(f开始转换: {mdb_path}) # 目标 gdb 不存在则创建 if not arcpy.Exists(gdb_path): gdb_name os.path.basename(gdb_path) arcpy.CreateFileGDB_management(os.path.dirname(gdb_path), gdb_name) arcpy.env.workspace mdb_path arcpy.env.overwriteOutput True # 处理要素数据集中的要素类 datasets arcpy.ListDatasets(, Feature) for ds in datasets: ds_out os.path.join(gdb_path, ds) if not arcpy.Exists(ds_out): arcpy.CreateFeatureDataset_management(gdb_path, ds) arcpy.env.workspace os.path.join(mdb_path, ds) for fc in arcpy.ListFeatureClasses(): arcpy.FeatureClassToGeodatabase_conversion(fc, ds_out) # 处理根目录独立要素类和表 arcpy.env.workspace mdb_path for fc in arcpy.ListFeatureClasses(): arcpy.FeatureClassToGeodatabase_conversion(fc, gdb_path) for tb in arcpy.ListTables(): arcpy.TableToGeodatabase_conversion(tb, gdb_path) write_log(f完成: {mdb_path} - {gdb_path}) # 主流程 for root, dirs, files in os.walk(root_dir): for file in files: if not file.lower().endswith(.mdb): continue # 拼完整路径和对应 gdb 路径 mdb_full os.path.join(root, file) gdb_full os.path.join(output_root, os.path.splitext(file)[0] .gdb) # 断点续传标记 marker gdb_full .done if os.path.exists(marker): write_log(f跳过已完成: {mdb_full}) continue try: convert_mdb(mdb_full, gdb_full) # 转换成功才写标记 open(marker, w, encodingutf-8).close() except Exception as e: write_log(f转换失败: {mdb_full}\n{traceback.format_exc()})4.2 脚本运行逻辑说明与参数调整建议这套脚本的运行逻辑是「扫目录 → 找 mdb → 转单个 mdb → 打标记 → 继续下一个」。几个参数值得按需调整root_dir和output_root分开配置是为了避免把输出的 gdb 又当成源数据扫进去——如果把输出目录放在源目录内部os.walk第二轮就会把刚才生成的 gdb 也扫进来反复膨胀这点我有过教训。marker使用gdb_full .done的命名保证每个 mdb 有独立的续传标记删掉标记文件即可强制重转某个库。convert_mdb里对数据集的空扫描做了防御性处理即便该 gdb 已经有同名数据集arcpy.Exists也会跳过创建步骤不会中断流程。有一个细节值得单独说这个脚本是串行处理的一个 mdb 转完才转下一个。如果你的机器性能不错、目录里 mdb 又多可以考虑按multiprocessing拆成并行任务但要注意并行时不要同时写同一个 gdb我一般按磁盘或按目录拆避免 I/O 撞车。4.3 失败重跑与删除标记后悔药怎么吃跑完一批后最常做的事就是检查日志里带转换失败的行。定位到具体是哪个 mdb 之后排查原因删除对应的.done标记文件如果有重新执行脚本它会自动只补转那个 mdb。这个流程比手动在工具箱里找数据再转一遍舒服太多了也是我向别人推荐这条技术路线时最有说服力的理由——整个流程可追踪、可重跑、可审计。5. 自动转换避坑指南五个最常翻车的坑与对应排查5.1 数据集内部的要素类漏转现象转完的 gdb 里只有一部分数据检查后发现丢的都是要素数据集内部的要素类。 原因ListFeatureClasses()默认只扫描当前 workspace 的顶层不会递归进要素数据集这是 arcpy 的既定行为不是 bug。 解决先ListDatasets(, Feature)拿到所有数据集再把 workspace 切换进数据集内部逐个扫描。代码写法见第 3 章 3.2 节这是多数人一开始写脚本最容易漏掉的一步。5.2 重复转换时报 999999 错误现象同一批脚本第二天重跑跑到一半直接报 ERROR 999999: 执行函数出错日志里没有别的明确提示。 原因目标 gdb 里已经存在同名要素类或表而overwriteOutput没有设为 True工具拒绝覆盖。 解决脚本开头加arcpy.env.overwriteOutput True。如果你希望保留旧 gdb 做备份就不要覆盖而是每次生成带时间戳的新 gdb 目录逻辑上是二选一。5.3 转换中途报「文件被占用」或「锁定」现象脚本跑到某个 mdb 时报错说文件正在被使用重跑同样卡在这一处。 原因mdb 被 ArcMap、ArcCatalog 或 Access 进程打开着。mdb 是 Access 底层结构默认使用共享锁机制其他进程占用时 arcpy 无法写入。 解决转换前关掉所有打开了该 mdb 的桌面程序如果线上环境实在没法保证就在脚本里针对这个错误做 try-except 捕获并跳过等占用解除后删除标记重跑。我一般习惯把这类 mdb 单独记录到日志里最后统一人工确认。5.4 Python 2 环境下中文路径直接报错现象在 ArcMap 自带的 Python 2.7 里跑脚本遇到中文文件夹名或中文要素名时抛 UnicodeDecodeError整个脚本中止。 原因Python 2 默认编码是 ASCII中文路径字符串没有正确解码成 Unicode。 解决最省事的方式是换到 ArcGIS Pro 的 Python 3 环境这类问题基本消失。如果必须用 ArcMap脚本头部写# -*- coding: utf-8 -*-所有路径字符串加u前缀比如uD:\数据\旧库.mdb。这算 Python 2 时代的老坑现在新项目建议直接上 Python 3。5.5 属性域、子类型与字段类型漂移现象转换完成后业务系统里发现某些字段由短整型变成了长整型某些属性域Domain和默认值消失了。 原因mdb 和 gdb 的底层字段体系不同转换工具会按内部映射规则处理类型部分对象类型如老版本 Access 特有的字段设置不会原样带过去。这不是脚本问题是格式升级本身的固有差异。 解决转换前用arcpy.ListFields导出源端字段清单转完后再导出目标端做对比属性域和子类型如果业务依赖单独用arcpy.TransferDomain_management或手动重建。说实话这类差异很多时候不影响查询统计只有下游系统按字段类型做硬校验时才会被发现提前对账能省掉不少麻烦。6. 转换后验证与进阶把脚本做成能长期复用的工具验证这步不能省。我每次批量转换完都会用一个对账脚本检查四件事要素类和表数量是否对上、关键表记录数是否一致、字段结构和主键是否完好、空间参考是否与源一致。记录数最直接挑几个关键表跑一下arcpy.GetCount_management对比源和目标的返回值即可字段结构用ListFields比对名称和类型空间参考用arcpy.Describe读取spatialReference.Name。数量差异大时先查日志多数是漏转了某个数据集。脚本本身可以继续进阶把输入输出目录包装成 ArcGIS 脚本工具Script Tool的参数面板让不懂代码的同事也能点按钮操作或者挂到系统计划任务里定时跑配合日志在失败时发邮件提醒。我现在养成的习惯是每次转换前先看一遍日志和历史标记确认数据源没有结构变更再执行跑完必对账对完再动业务系统——这套流程用了很久几乎没再出过漏数据的事故。希望帮到你。本文还有配套的精品资源点击获取