☰
DWG转SHP属性不丢:CADSHAPE环境配置与批量转换避坑指南
2026/10/26 8:59:03 网站建设 项目流程

简介:这是一款面向CAD与GIS数据互转场景的轻量插件包,聚焦AutoCAD 2008环境下CAD图形与Shapefile之间的带属性转换。使用者可通过XDATA查看、XDATAEDIT编辑图形扩展属性,并借助LOADSHP、EXPSHP完成Shapefile加载与CAD图元导出,无需额外运行环境即可开展数据转换。压缩包共12个文件,以7个dll动态链接库为核心,配套3个xml配置、1个txt使用说明及1个pdb调试文件,整体约877KB,体积小巧、部署直接。已有4527人学习下载,适合需要处理带属性图形转换的测绘、规划及GIS入门至中级用户参考。插件将属性读写、图形加载与导出命令集中在CAD界面内,便于在现有制图流程中完成CAD与SHP的双向衔接,也为理解扩展属性与空间数据字段对应关系提供了可操作样本。

1. 一批 DWG 撑了三天返工,问题不在转换按钮

前年接手一批竣工图入库,甲方给的是 DWG,要的是带属性的 SHP。我图省事,直接拿工具点了一下导出,几何全过来了,属性表里只剩 FID、Layer 和 Elevation——块参照里明明填了管径、材质、埋深,一个都没跟过来。返工三天,最后查出来原因很朴素:机器上根本没装对 CAD 解析组件,插件静默走了兜底分支,只读了图形不读扩展数据。

CADSHAPE 带属性转换这类活,装环境占七成,点按钮占三成。这篇记录写给手上有一批 DWG 要转 SHP、且属性不能丢的人:测绘入库、管线普查、规划报建、地籍成图都算。装错一步,后面全是黑匣子。

2. 环境清单:四条安装路线和一组能对上的版本号

动手前先把路线定下来,不同路线的插件挂载方式、字段处理能力、批量能力完全不同,装完再改路线等于重来。我一般按「有没有 ArcGIS 许可」「要不要跑批量」「数据量多大」三个问题来分流。

2.1 四条路线的取舍,别一上来就装全套

第一条是 ArcGIS Pro 路线,插件以工具箱(.pyt 或 .tbx)形式挂进去,好处是坐标系定义、字段类型推导、几何修复这些环节都有现成能力兜底,坏处是 Pro 的 Python 环境是独立的 conda 环境,外部装的包不会自动进去。第二条是 ArcGIS Desktop 10.x 路线,32 位进程,Python 2.7,超过两三百兆的 DWG 基本必崩,能不用就不用。

第三条是 QGIS 路线,插件本质是处理提供者或脚本,底层跑 GDAL/OGR,免费、可控、能开日志,适合没有商业许可的团队。第四条是纯命令行路线,服务器上 conda 建一个环境,写脚本批量跑,最适合上千个文件排队转换的场景,也最容易做失败重试。四条路线里,我通常选第三条做首轮验证,确认属性提取逻辑对了,再迁到第四条跑批量。

需要说清一点:GDAL 的 DXF 驱动能直接读 DXF,但读 DWG 要额外的商业解析库。所以不管走哪条路线,稳妥流程都是「DWG 先用转换器批量转 DXF,再由 OGR 读 DXF 出 SHP」。这一步多花十分钟,能省掉后面一堆几何丢失的排查。

2.2 版本对照表:对不上就是各种玄学报错

组件推荐版本作用常见不匹配后果
Python3.9 或 3.10主运行环境3.11 以上部分 GDAL wheel 还没跟上
GDAL/OGR3.4 及以上读写 DXF、SHP低于 3.0 时 DXF 驱动对块属性支持弱
pyshp2.3 及以上直接写 DBF 字段老版本不生成 .cpg,中文必乱码
pyproj3.4 及以上坐标系定义与转换与 PROJ 数据版本错位会报 proj_create 失败
shapely2.0 及以上几何修复与合并1.x 与 2.x API 不兼容,脚本要改
ODA File Converter跟随官方最新DWG 转 DXF版本太旧读不了新版 DWG
ArcGIS Pro3.x工具箱宿主Pro 3.x 的 Python 是 3.9,2.8 及以前是 3.7

表里最容易翻车的是 Python 位数。ArcGIS Desktop 是 32 位,绑的是 32 位 Python 2.7;你在外面装个 64 位 Python 3.9,插件再怎么写都加载不进去,报的错误还往往是「找不到指定模块」,看起来跟位数毫无关系。

2.3 安装命令与装完立刻要跑的三条自检

我习惯用 conda 建独立环境,不污染系统 Python,出问题直接删环境重来,这就是后悔药。

# 建一个专用环境,python 版本按上表选 conda create -n cad2shp python=3.9 -y conda activate cad2shp # GDAL 优先用 conda-forge 渠道,省掉自己编 wheel 的麻烦 conda install -c conda-forge gdal=3.6 pyproj shapely -y # 纯 python 的 shapefile 读写库走 pip 即可 pip install pyshp==2.3.1

conda 渠道的好处是 GDAL、PROJ、GEOS 这几个底层库的版本会一起解算,不会出现 GDAL 认不出 PROJ 数据目录的情况。如果用 pip 装 GDAL,必须装与本机已编译版本严格一致的预编译包,装错了报错信息通常只有一句 DLL load failed,看不出根因。

装完立刻跑三条命令,别急着挂插件:

# 1. 确认 GDAL 版本与 python 绑定正常 python -c "from osgeo import gdal; print(gdal.__version__)" # 2. 确认 DXF 驱动在列,没有就说明编译时被裁掉了 ogrinfo --formats | findstr /i dxf # 3. 确认坐标系数据库能读到,这条最容易静默失败 python -c "from pyproj import CRS; print(CRS.from_epsg(4547).name)"

第二条在 Linux 或 macOS 上把 findstr 换成 grep。第三条如果抛异常,八成是 PROJ_LIB 指向了错误目录,先别往下走,环境变量那节会讲怎么修。

2.4 装之前先做的四项检查

第一项,安装路径全英文。conda 环境、插件目录、输入输出目录,任何一个路径带中文或空格,都可能让命令行工具在解析参数时截断,表现是「文件明明在,就是读不到」。

第二项,位数对齐。跑python -c "import struct;print(struct.calcsize('P')*8)",输出 32 就说明是 32 位解释器,只能挂 32 位的宿主。

第三项,写权限。插件目录如果在 Program Files 下,普通账户写配置文件会被拦,转换到一半写不出日志,看起来像卡死。

第四项,安全软件白名单。批量转换会短时间内产生大量小文件(.shp/.shx/.dbf/.prj/.cpg),容易被实时扫描拖慢十倍,必要时给输出目录加例外。

3. 插件挂载:解压、注册、让宿主认得出它

环境备好,接下来是把插件真正挂到宿主里。这一步的坑集中在「宿主用的是哪个 Python」和「依赖装到了哪个 Python」这两件事上。

3.1 解压后的目录该长什么样

解压出来先别急着双击。正常结构一般包含入口文件(.pyt、.tbx、.esriaddin 或一个主脚本)、若干模块目录、一个配置文件模板,以及说明文档。先确认三件事:入口文件在不在、依赖清单里写了什么、有没有附带的二进制库(.dll 或 .so)。

如果目录里带 .pyd 或 .dll,注意它的编译位数和目标 Python 版本,这两个对不上,import 阶段就失败。我一般的做法是把整个插件目录放到一个短路径下,比如D:\gis\cad2shp_plugin,路径越短,后面命令行调用时越不容易出问题。

3.2 挂进 ArcGIS Pro 的两种方式

第一种是工具箱方式:在 Pro 的目录窗格里右键「工具箱」→「添加工具箱」,选中 .pyt 文件,之后工具会出现在目录树里,双击即可运行。这种方式最省事,缺点是参数面板是 Pro 自动生成的,字段映射这类复杂配置只能靠下拉框凑。

第二种是脚本工具方式:新建工具箱,添加脚本,把解释器指向 Pro 自带的 conda 环境。这个环境的位置大致在安装目录下的bin\Python\envs\arcgispro-py3,具体路径以本机为准。

# 用 Pro 自带环境装依赖,不要用系统 python "C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\python.exe" -m pip install pyshp # 装完在同一个解释器里验证,能 import 才算进去 "C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\python.exe" -c "import shapefile; print(shapefile.__version__)"

这里的关键是「用哪个解释器装,就用哪个解释器验」。很多人习惯在 cmd 里直接 pip install,装进了系统 Python,Pro 跑脚本时用的是自己的环境,照样报 ModuleNotFoundError。判断方法很简单:在 Pro 的 Python 窗口里执行一次import sys; print(sys.executable),打印出来的路径就是它真正在用的解释器。

如果要装 GDAL 这类带二进制的包,Pro 环境里优先用它自带的包管理器,别硬怼 pip,否则容易出现 arcpy 与 GDAL 抢同一个底层库的情况。

3.3 挂进 QGIS 与纯命令行环境

QGIS 路线下,插件一般以脚本形式注册到处理工具箱,脚本开头会声明输入图层、输出路径、坐标系、字段映射等参数。注册前先确认 QGIS 自带的 Python 环境里有没有依赖:

# QGIS 自带 python 的调用方式,路径按本机安装位置调整 python-qgis -c "from osgeo import ogr; print(ogr.GetDriverByName('DXF'))"

输出不为 None,说明 DXF 驱动可用。如果返回 None,多半是 QGIS 版本自带的 GDAL 被裁剪过,那就退回命令行路线,用独立 conda 环境跑,别在 QGIS 里死磕。

纯命令行路线最直接,把插件主脚本当普通 Python 脚本调用:

conda activate cad2shp python D:\gis\cad2shp_plugin\main.py --input D:\cad_in --output D:\gis_out ^ --config D:\gis\cad2shp_plugin\config.json --epsg 4547 --encoding utf-8

参数含义:--input 指向 DXF 所在目录,--output 是 SHP 输出目录,--config 指定映射配置,--epsg 定义输出坐标系,--encoding 控制 DBF 的字符编码。Windows 下换行用 ^ 续行,Linux 下换成 \。第一次跑建议只放两三个小文件,确认流程通了再上全量。

3.4 环境变量:三个必须指对的目录

GDAL_DATA 指向 GDAL 的坐标转换辅助数据目录,PROJ_LIB 指向投影定义库目录,这两个指错,坐标系相关功能会以各种奇怪的方式失败——比如投影转换结果差几百米,或者 EPSG 码认不出来。第三个是 PATH 顺序,机器上装了多个 GDAL 时,PATH 里排在前面的那个生效,版本可能跟你预期的完全不同。

# Windows 下临时设置,只在当前会话生效,适合排错时用 set GDAL_DATA=D:\envs\cad2shp\Library\share\gdal set PROJ_LIB=D:\envs\cad2shp\Library\share\proj set PATH=D:\envs\cad2shp\Library\bin;%PATH% # 验证:能打印出正确的投影名称就说明指对了 python -c "from pyproj import CRS; print(CRS.from_epsg(4547).name)"

用 conda 环境时,激活环境本身就会设置好这几个变量,所以最省事的办法是永远在激活状态下工作,别混用系统环境。临时排错才用上面这种手动设置,排完记得清掉,避免留下一个看不见的污染源。

3.5 冒烟测试:三分钟确认装没装歪

挂载完成后先做一个最小闭环:拿一张只有两条多段线、一个带属性块的小 DXF,跑一次转换,看输出目录里是否生成了 .shp、.shx、.dbf、.prj、.cpg 五个文件。

少 .prj 说明坐标系没写进去,少 .cpg 说明编码没声明,这两个缺一个,后面 ArcGIS 打开时都会有异常表现。打开属性表看一眼,块里填的属性值是不是在对应的字段里。这一步过了,再谈批量。

4. 配置参数:属性从哪来、字段怎么落、坐标怎么定

插件装通了只是开始,真正决定成图质量的是配置。CAD 里的信息散落在图层名、块属性、文字注记、扩展数据四个地方,配置的核心就是告诉插件「去哪里取、取到哪个字段、怎么处理超长和空值」。

4.1 输入输出与坐标系三件套

坐标系这块要定三件事:源数据的单位、目标坐标系、是否做单位换算。

CAD 图里常见的坑是单位。同一张管线图,有人按毫米画,有人按米画,转成 SHP 时如果不做换算,整张图会偏移一千倍。判断方法是在 CAD 里量一段已知长度的对象,看读数跟实际差多少个数量级。

目标坐标系按业务要求填 EPSG 码,比如投影坐标系常用 4547 这类三位数以上的编码,地理坐标系常用 4490。填之前确认数据本身带不带投影信息,CAD 一般不带,需要人工指定。

{ "input": { "dir": "D:/cad_in", "dxf_version": "ACAD2018", "unit_scale": 0.001 }, "output": { "dir": "D:/gis_out", "epsg": 4547, "encoding": "utf-8", "overwrite": true } }

unit_scale 为 0.001 表示源图按毫米绘制、目标按米存储;源图本来就是米,这个值填 1。这个参数填错的后果比坐标系填错更直观——坐标系错了是整体位移,单位错了是比例尺全乱。

4.2 属性来源的四种形态与提取优先级

块属性(ATTRIB)是信息最全的一类,管径、材质、埋深这些结构化字段通常存在这里。文字注记(TEXT/MTEXT)内容自由、格式混乱,只能整段搬进备注字段。扩展数据(XData)是二次开发写入的,字段名往往有固定前缀。图层名最简单,直接作为分类字段。

优先级我一般这样排:块属性优先,扩展数据次之,文字注记作为补充,图层名兜底。原因是块属性结构最规范、最不容易错位;文字注记一旦混进无关标注,整列都是脏数据。

块属性要提取出来,前提是块参照被正确解析。有些插件默认不炸开块,只读 INSERT 的插入点和块名,属性自然全空。配置里找「炸开块」或「提取块属性」这类开关,打开之后再跑一次小样本对比。

扩展数据的读取依赖 DXF 里的 1001 组码,这块 GDAL 的支持程度跟版本关系很大,版本低了读不到,表现就是某个字段整列为空。遇到这种情况先升 GDAL,别急着改配置。

4.3 字段映射与 SHP 的硬限制

SHP 的 DBF 有几个绕不过去的限制,配置阶段就得处理掉,别指望转换完再改:

限制项具体规则处理方式
字段名长度最多 10 个字符映射表里预先缩写,如 DIAMETER→DIAM
文本字段宽度最多 254 字符超长文本截断,或拆成两个字段
字段名唯一前 10 字符不能重名加数字后缀区分,如 MATER、MATER2
空值DBF 不支持真正的 NULL数值补 0、文本补空串,下游按约定判断
单文件大小传统 SHP 有 2GB 上限超过就按图幅或图层拆分

字段名截断是个隐蔽坑:插件自动把中文字段名转成拼音或直接截断,转完发现两个字段都叫 ATTRIB_1、ATTRIB_2,对不上业务列。稳妥做法是配置里显式写映射表,源字段名和目标字段名一一对应,不依赖自动推导。

{ "field_map": [ { "src": "管径", "dst": "DIAM", "type": "real", "width": 10, "decimals": 2 }, { "src": "材质", "dst": "MATER", "type": "string", "width": 32 }, { "src": "埋深", "dst": "DEPTH", "type": "real", "width": 8, "decimals": 2 }, { "src": "编号", "dst": "CODE", "type": "string", "width": 24 } ] }

type 决定 DBF 里落成数值型还是字符型。数值型不要给宽度 0,否则小数位会被抹掉;字符型宽度按实际内容乘 1.5 留余量,中文在 GBK 下占两个字节,宽度按字符数算常常不够。

4.4 批量任务与错误隔离

上百个文件排队转换时,最怕的是中间一个文件报错,整批任务中断,前面跑完的也不知道跑没跑全。稳妥写法是外层循环加异常捕获,单个文件失败只记录不中断:

import subprocess, pathlib, json failed = [] for dxf in pathlib.Path(r"D:\cad_in").glob("*.dxf"): cmd = ["python", r"D:\gis\cad2shp_plugin\main.py", "--input", str(dxf), "--output", r"D:\gis_out", "--config", r"D:\gis\cad2shp_plugin\config.json"] r = subprocess.run(cmd, capture_output=True, text=True) # 返回码非 0 视为失败,把 stderr 前 200 字符记下来方便定位 if r.returncode != 0: failed.append({"file": dxf.name, "err": r.stderr[:200]}) continue print(json.dumps(failed, ensure_ascii=False, indent=2))

subprocess 用列表传参而不是拼字符串,避免路径里有空格时被截断。capture_output 把日志收回来,单文件失败时能立刻知道是解析错误还是写文件权限问题。failed 列表就是这次批量的失败清单,重跑只针对它。

并发别开太高。每个转换进程都要加载一遍 GDAL 和 CAD 解析库,四五个并发就能把内存吃满,尤其 32 位进程,超过两个必然出问题。我一般按核数的一半起步。

5. 避坑排查:五条血泪经验,每条都能省半天

5.1 属性表里中文全是问号

现象:转换完成,属性表能打开,但中文字段值显示成问号或方块,英文数字正常。

原因:DBF 文件没有 .cpg 声明文件,或者声明成 UTF-8 而宿主按系统代码页解释。SHP 的文本编码不是自描述的,全靠 .cpg 这个附带文件,缺了它各家软件就各按各的默认值猜。

解决:配置里显式指定 encoding 为 utf-8,转换后确认输出目录里有 .cpg 且内容为 UTF-8。如果宿主是老版本 ArcGIS,读 UTF-8 反而乱,那就退回 GBK,但要在团队内统一,别一半 GBK 一半 UTF-8。

5.2 某个属性列整列为空,一个值都没有

现象:几何完全正确,图层、颜色都转出来了,唯独块属性那几个字段全空。

原因:三种可能——块没被炸开导致只读了 INSERT 实体、GDAL 版本太低不支持对应的扩展数据组码、字段映射表里的源字段名跟 CAD 里的实际标签名对不上(多一个空格也算对不上)。

解决:先用只含一个块的极小 DXF 做对照实验,逐项排除。用 ogrinfo 直接看 DXF 的字段名,跟映射表逐字符比对。这一步最快,往往一眼就能看出标签名里有隐藏空格。

5.3 转出来的图整体偏移,或者比例完全不对

现象:SHP 加载到地图里,跟底图差了十万八千里,或者图形大小差一千倍。

原因:CAD 里不携带投影信息,转出来如果没指定 EPSG,SHP 就是「无投影坐标」,ArcGIS 会按第一个加载的图层坐标系硬套。比例不对则是单位换算系数没设,毫米当米用了。

解决:转换时必填 EPSG,转换后用 ogrinfo 确认 .prj 里的坐标系名称。比例问题用一段已知长度的对象核对,量出来差三个数量级就是毫米转米没做。

5.4 跑到一半进程消失,没有任何报错

现象:命令行窗口直接退出,日志最后一行停在某条几何处理上,没有异常堆栈。

原因:32 位进程的内存上限,大图里几万个块参照炸开之后内存直接打满,操作系统强杀进程。这种情况不会有任何 Python 层面的报错。

解决:换 64 位环境和 64 位宿主,或者按图层、按图幅拆分输入。拆分之后如果还崩,看是不是某个块里有异常几何在死循环,把那个块单独提出来测。

5.5 import 时报 DLL load failed

现象:脚本本身能跑,一执行 from osgeo import ogr 就报找不到指定模块。

原因:GDAL 的二进制依赖没进 PATH,或者机器上存在多个 GDAL,加载到的是位数或版本不匹配的那一个。混装 conda 和 pip 版本的 GDAL 是最常见的诱因。

解决:进环境后执行where gdal*.dll看清楚有几个、分别在哪。保留一套,其余从 PATH 里摘掉。实在理不清就删环境重建,比逐个排查快得多。

6. 装完怎么验证:五步验收加一段自动比对

转换脚本跑完不出错,不等于数据能用。我固定走五步验收:一看文件完整性,二看要素数量,三看坐标系,四看属性非空率,五看几何有效性。

文件完整性看输出目录里是不是每个 SHP 都配齐 .shp、.shx、.dbf、.prj、.cpg 五个文件。要素数量用 ogrinfo 拿,跟源头粗对一遍:

# 只看汇总信息,不打印每条要素,大文件也能秒出 ogrinfo -so -al D:\gis_out\gas_line.shp

重点看 Feature Count 和 Extent 两项。Extent 的数值范围能立刻暴露坐标单位问题——如果坐标值在几百万量级,多半是投影坐标没做换算。

属性非空率用脚本统计,比人工翻属性表靠谱:

from osgeo import ogr ds = ogr.Open(r"D:\gis_out\gas_line.shp", 0) lyr = ds.GetLayer(0) n = lyr.GetFeatureCount() defn = lyr.GetLayerDefn() fields = [defn.GetFieldDefn(i).GetName() for i in range(defn.GetFieldCount())] # 逐字段统计非空要素数,非空率过低说明映射或提取环节有问题 stat = {f: 0 for f in fields} for feat in lyr: for f in fields: if feat.GetField(f) not in (None, ""): stat[f] += 1 for f, c in stat.items(): print(f"{f:>10} {c}/{n} {c / n:.1%}")

GetField 对数值型返回 0 而不是 None,空值判断要按字段类型分开写,数值型看是否为 0 之外的合理值。跑完这份输出,哪一列非空率明显偏低,就回到第 5 章第 2 条去查。

几何有效性用 OGR 的检查能力扫一遍,重点看有没有自相交或零面积面:

ogrinfo -sql "SELECT COUNT(*) FROM gas_line WHERE ST_IsValid(geometry) = 0" D:\gis_out\gas_line.shp

输出为 0 才算过关。不为 0 就用修复工具处理,别带着脏几何入库。

最后一步是抽样核对。从 CAD 里随机挑五个带属性的块,记下它们的编号和属性值,在 SHP 属性表里按编号查,逐个对。五个全对,基本可以认为映射逻辑没问题;有一个不对,就把那个块单独提出来做对照实验。

从那以后我每次装完这套环境,都会先用一张只有两条线一个块的小 DXF 跑通全流程,再上正式数据。冒烟测试三分钟,能挡掉后面百分之八十的返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询