CAD转SHP带属性转换插件:从原理到实战,解决字段丢失问题
简介面向GIS及测绘工作人员的CAD与SHP格式互转工具插件基于CAD2008环境即可实现带属性数据的无缝转换。资源包内包含核心转换功能DLL库、配置文件XML以及一份使用说明文档共12个文件整体仅877KB轻量易用。插件提供XDATA、XDATAEDIT、LOADSHP、EXPSHP四条命令可便捷查看、编辑CAD扩展属性并能在CAD与Shapefile之间双向加载导出图形及属性信息。当前已有4522人学习下载适用于需要批量处理CAD图纸和GIS数据转换的项目场景。包内除核心动态库外还附带运行配置与说明文档方便快速部署与上手。1. CAD 转 SHP 带属性这件事先搞清楚为什么总要丢字段做管线普查、竣工图入库、地籍整理的人大概率都经历过这么一幕CAD 图纸拿到了GIS 图层建好了结果一顿常规转换操作下来SHP 里只剩几何体井号、管径、材质、高程这些业务字段全丢了等于画了个空壳。这就是 CADSHAPE 带属性转换要解决的核心问题——不是能不能转而是属性丢不丢。这份插件按 CAD 实体类型分流处理普通线体转几何文字注记进字段图块属性映射成 DBF 列最后输出带 .prj 坐标文件的完整 Shapefile。它适合两类人一是做数据入库、批量整理历史 CAD 资料的测绘工程师二是被临时要求今天把这几百张图转成 SHP 还要带属性的一线现场人员。下面按拆包、原理、跑通、避坑、进阶五步展开新手能照步骤走熟手直接跳第四章看坑。2. 插件的两条主线几何怎么提属性怎么带2.1 压缩包里能拆出什么三个文件加一个样例目录一份能落地的转换插件不会只丢一个脚本给你。我拆过的同类资源里比较标准的组织方式是下面这样CAD转SHP带属性插件/ ├── cad2shp.py # 主转换程序命令行入口 ├── attrib_map.json # 属性映射配置决定哪些 CAD 属性进哪些字段 ├── requirements.txt # Python 依赖清单 ├── README.md # 使用说明含命令行参数和已知限制 └── sample/ ├── 管线样例.dwg # 测试数据带图块属性 └── 输出示例/ # 作者跑好的结果用来对照验证主程序负责两件事读 CAD 实体、写 SHP 文件。映射配置单独拆成 JSON是因为不同项目的图块属性名完全不一样有的叫井号有的叫井编号还有的下划线后缀不同。硬编码在代码里每换一个项目改一次脚本迟早改乱。拆出来以后改配置就行代码一行不动。README 我建议先花十分钟看一遍里面通常写清了依赖版本、运行方式和已知限制很多坑其实文档里已经写了只是没人看。sample 目录是验证用的拿到插件第一件事就是拿样例图跑一遍确认结果和输出示例一致再上自己的图这一步能省掉后面大量的排查时间。注意SHP 是四件套.shp 存几何.dbf 存属性.shx 是索引.prj 是坐标参考。很多第一次用的人只拷了 .shp 就走在 GIS 里打开报缺少 .shx或者属性表空白其实不是转换的问题是文件没带全。2.2 属性从哪来文字注记、图块属性与扩展数据很多人以为 CAD 的属性就是图形旁边那行字其实按来源分至少有四类TEXT / MTEXT 文字实体独立注记内容存在实体自身的文本串里转换时可以直接取INSERT ATTRIB 图块属性比如检查井块里的井号井底高程管径以标签-值成对挂在块引用上扩展数据 XDATA第三方管线软件写进实体的业务字典键值对形式需要单独解析实体公共头图层名、颜色、线型、线宽、标高这些也算属性是每个实体都有的。插件读取时逐实体遍历模型空间按类型分流。文字实体直接取文本串图块实体要递归进块表定义把 ATTRIB 当成键值对收进字典对 CIRCLE、ARC 这类曲线实体先按参数离散成折线再输出。普通转换工具之所以丢属性是因为它们只做了第 4 类公共头的拾取甚至图层名都不一定保留对第 1、2 类完全不碰。而带属性转换的核心就是补上这几层抽取。核心抽取逻辑长这样import ezdxf def extract_entity_attrs(entity, msp): rec { LAYER: entity.dxf.layer, HANDLE: entity.dxf.handle, ENT_TYPE: entity.dxftype(), TEXT: , ELEV: getattr(entity.dxf, elevation, 0) # 不是所有实体都有标高用 getattr 兜底 } if entity.dxftype() in (TEXT, MTEXT): # TEXT 直接取 dxf.textMTEXT 用 entity.text 拿剥掉格式码的纯文本 rec[TEXT] entity.dxf.text if entity.dxftype() TEXT else entity.text elif entity.dxftype() INSERT: # 图块属性遍历 ATTRIB按标签 tag 收集中文名先原样保留 for attrib in entity.attribs: rec[attrib.dxf.tag] attrib.dxf.text return rec逻辑说明函数按实体类型返回一个字典公共字段 LAYER、HANDLE、ENT_TYPE、ELEV 每个实体都有。TEXT 实体把文本写进 TEXT 键MTEXT 用 entity.text 取纯文本ezdxf 会自动处理多行文本的内部格式控制符。INSERT 实体通过 attribs 迭代器把属性标签作键、属性值作值塞进字典这一层先不转字段名等写 DBF 时再统一映射。参数说明HANDLE 是字符串形式的十六进制句柄在 CAD 里可以按 Handle 反查定位实体强烈建议保留ENT_TYPE 存的是 DXF 类型名比如 LINE、CIRCLE、INSERT方便后续在 GIS 里做符号化分类。2.3 字段映射规则中文属性名怎么变成 ASCII 字段DBF 的字段名规则很老10 个字符以内、推荐 ASCII 大写。中文名在一些 GIS 平台里要么乱码要么直接读不出来所以插件不会把井号直接当字段名而是通过 attrib_map.json 做一次映射。默认字段加业务字段转换后的 DBF 大概长这样LAYER、HANDLE、ENT_TYPE、TEXT、ELEV然后是 WELL_NO、DIAMETER、MATERIAL 这些业务列。对应的配置文件{ input_encoding: gbk, output_encoding: utf-8, shp_type: auto, default_fields: [LAYER, HANDLE, ENT_TYPE, TEXT, ELEV], attr_map: { 井号: WELL_NO, 管径: DIAMETER, 材质: MATERIAL, 埋深: BURY_DEPTH } }逻辑说明attr_map 的键是 CAD 图块属性标签值是输出的字段名。插件每读到一个属性标签先查映射表命中就用 ASCII 名建字段没命中就丢弃并写日志。input_encoding 决定读 CAD 内部字符串时按什么字符集解码output_encoding 决定 DBF 用什么编码写。参数说明shp_type 设 auto 时插件按几何类型自动拆成点、线、面三个 SHP如果业务只导管线设成 line 能省掉多边形检测的开销。output_encoding 建议保持 utf-8旧项目里如果有老 GIS 平台不认 UTF-8 的 DBF改成 gbk 再试。这里有个取舍要说明CAD 里一个图块可以挂几十个属性但业务真正用到的可能就三五个。映射表只留要用的那几个能让 DBF 干净很多。剩下的属性不是丢了只是没带进来真需要的时候在映射表里加一行再重跑即可。全量保留的后果是 DBF 里塞满旋转角、比例因子、重复的属性定义这类对业务没意义的字段入库前还得手工删。3. 跑通第一条转换环境、命令与结果校验3.1 先把依赖装对ezdxf、pyshp 与 pyproj 的分工这个插件栈里三个库各管一段ezdxf 读 DXF 实体和属性pyshp 负责写 Shapefilepyproj 做坐标参考系变换。装依赖pip install ezdxf pyshp pyproj逻辑说明三个库都是纯 Python 实现装完就能跑不需要装 CAD 软件本体也不需要装 GIS 平台。ezdxf 是目前开源生态里对 DXF 支持比较全的解析库支持 R12 到 R2018 的 DXF 版本pyshp 是最常用的纯 Python SHP 读写库API 简单写 DBF 时能精确控制字段名和字段类型pyproj 是 PROJ 的 Python 绑定坐标系转换全靠它。参数说明如果你的 Python 是 3.10 以上的新版本直接装这三个包没有兼容性问题如果是老机器上自带的 Python 2 环境建议单独建一个虚拟环境避免依赖冲突。装完跑一句验证python -c import ezdxf, shapefile, pyproj; print(deps ok)输出 deps ok 表示环境就绪。这里要提醒一句DWG 不是公开格式ezdxf 只读 DXF直接喂 DWG 大概率报格式不支持。装完依赖先确认手上文件是 DXF 还是 DWG这决定下一步走哪条分支。3.2 DWG 转 DXF跑插件前必做的前置步骤如果手头全是 DWG先用免费转换器批量转成 DXF常见做法是装一个 DWG→DXF 转换器完全离线批量处理。转换器参数一般就两个目标版本选 2007 或 2010输出目录指定好。2007 版 DXF 兼容性最好老版本 CAD 和新版本都能打开插件读起来也稳。dwg2dxf --input ./dwg_all/ --output ./dxf_all/ --version 2007逻辑说明这是转换器的命令行形式把整个目录的 DWG 一次性转成 DXF 2007。转完检查输出目录DXF 文件数量应该和 DWG 一致有失败的单独看报错。参数说明--version 指定 DXF 版本不是越新越好2018 版 DXF 对老工具不一定友好转换器默认按文件同名输出目录结构会保留。注意转换这一步不会丢属性图块属性、文字注记都还在可以放心转。转换器转出来的 DXF 可能混合了多种字符编码插件读的时候按 input_encoding 统一解码所以 DWG 阶段如果混着 GBK 和 UTF-8 两种来源的文件建议按来源分目录转分别建配置避免同一批里两种编码互相干扰。提示DWG→DXF 转换不会丢属性和文字可以放心批量处理这步别自己写脚本解析 DWG 二进制吃力不讨好。3.3 单文件转换命令参数逐个说第一次转换直接用样例数据python cad2shp.py -i sample/管线样例.dxf -o out_sample/ -c attrib_map.json逻辑说明-i 指定输入 DXF-o 指定输出目录-c 指定映射配置。插件遍历模型空间按配置抽取属性最后在输出目录生成 .shp、.dbf、.shx、.prj 四个文件。参数说明输出目录不存在会自动创建同名文件不会覆盖会提示换目录或加 --force 强制覆盖配置文件不传时用默认映射只输出公共字段业务属性全部丢弃新手最容易漏掉 -c 参数结果转完又说属性没了。跑完终端会打印统计读取实体 1284 个其中 TEXT 356INSERT 421LINE 507 输出点要素 421 条线要素 507 条文本要素 356 条 写入 out_sample/管线样例.shp 完成这个统计对得上是最基本的验证。实体总数 1284输出 1284说明没有实体被静默丢弃如果对不上说明有实体类型没进分流逻辑日志里会给出警告。常用命令行参数整理成表参数作用常见取值-i / --input输入 DXF 或 DWG文件路径-o / --output输出目录目录路径-c / --config属性映射配置attrib_map.json--layer-filter只转指定图层图层名或通配符--scale坐标缩放系数0.001毫米转米--force覆盖同名输出开关默认关参数说明--layer-filter 在图层很乱的图里很有用比如只要给水排水两个图层写成--layer-filter 给水,排水其余图层不输出--scale 解决单位问题CAD 用毫米、SHP 用米时设 0.001坐标整体缩放不需要动源文件。3.4 转完别急着入库先做属性对照检查拿到 SHP 先别往 GIS 里导用 pyshp 读一遍字段和记录最快import shapefile sf shapefile.Reader(out_sample/管线样例.shp) print(要素数:, len(sf)) print(字段列表:, [f[0] for f in sf.fields[1:]]) # 第一项是 DeletionFlag从 1 开始取 for i in range(3): print(sf.record(i))逻辑说明这段代码把 SHP 的字段名和头三条记录打出来。要素数应该和转换统计里的输出数一致字段列表里能看到 WELL_NO、DIAMETER记录值要和 CAD 原图属性对得上。参数说明sf.fields 的第一项是内部删除标记字段取字段列表要从下标 1 开始record(i) 返回的记录值顺序和字段列表一致可直接按位置对齐。如果 WELL_NO 是空字符串多半是图块属性标签不叫井号回到 CAD 里用属性面板查实际 tag改映射表键名重跑。对照检查重点就两个数量对不对值对不对。数量对、值不对优先怀疑编码值对、数量不对优先怀疑实体类型分流。这一步花两分钟能挡住后面入库返工的大麻烦。4. 避坑指南编码、坐标和属性丢失的五个典型问题这五个坑是我在多个转换项目里实际撞过的按出现频率排了个序。每个都按现象 → 原因 → 解决写你在自己的数据上遇到同类问题直接对号入座。4.1 现象中文字段值全是问号转完打开属性表井号、材质全是????或者干脆是乱码。原因是 CAD 里文字按 GBK 存储插件却按 UTF-8 解码或者正好反过来源文件是 UTF-8 却按 GBK 解。解决先确认图纸编码。最直接的办法是用文本编辑器打开 DXF看头部 $DWGCODEPAGE 声明ANSI_936 就是 GBKUTF-8 会有明确标识然后把 attrib_map.json 里的 input_encoding 改成图纸实际编码。输出端 output_encoding 保持 utf-8 即可当代 GIS 平台基本都认。改完重跑乱码基本消失。这个坑频率最高十个转 SHP 的项目里至少三个栽在这而且不容易自查因为几何看起来完全正常。4.2 现象SHP 打开了属性表一片空白图层、几何都在但 DBF 里除了默认字段没别的内容。原因多半是遍历逻辑只处理了 LINE、CIRCLE 这类基础实体图块 INSERT 里的 ATTRIB 没进抽取流程或者属性写在 XDATA 扩展数据里而插件没解析这一段。解决先在 CAD 里选中一个检查井看属性面板确认属性是块属性还是扩展数据。块属性 tag 对不上映射键就改 attrib_map.json如果是 XDATA要么找插件里是否带扩展数据解析的开关要么自己补一段按字典键提取的代码。还有一种伪装情况属性其实是块旁边的独立文字注记不是真正的 ATTRIB插件读不到只能接受用 TEXT 字段承载内容或者在前处理里把注记批量转成真属性。这一步是带属性转换最容易翻车的地方比乱码更隐蔽因为转换日志里看不出任何异常。4.3 现象转出来的坐标在 GIS 里偏出几百米几何明显不在底图位置上比例尺对就是整体偏移或整体错位。原因有两个一是 CAD 坐标系和 GIS 底图坐标系不一致源数据是地方坐标系、任意坐标系直接转没做变换二是单位问题CAD 常用毫米SHP 标准单位是米没做缩放就相当于整体缩小了 1000 倍。解决先用已知控制点比如道路交叉口量一下两份数据的坐标差确认是整体平移还是缩放然后在配置里加 source_epsg 和 target_epsg 两个参数插件用 pyproj 在写文件前做投影变换单位问题用 --scale 0.001 处理。source_epsg 一般能从测绘成果说明里找到找不到就按图廓和公里网标注反推投影带。坐标错位不是玄学就是坐标系和单位两个变量没对上逐个排查即可。4.4 现象圆弧、圆转成 SHP 后变成折线弧段不光滑SHP 格式不支持圆弧实体只能把弧线离散成线段离散密度不够就出现折角弯头处最明显。原因是弦高或分段数参数设得太粗圆转出来像多边形。解决调整插件里的离散参数常见做法是按弦高控制1:500 地形图弦高取 0.05 米就够1:10000 的大比例尺图可以放宽到 0.5 米或者按圆心角控制每段不超过 1 度。代价是输出文件变大节点数成倍上涨大图要先权衡要不要全图统一加密。做管线转 SHP 时我一般先用一个弯头密集的小图试参数看着折线变光滑了再铺开跑全量避免一整批转完才发现弯头都是锯齿。4.5 现象DWG 直接转换报格式不支持或文件读取失败开源库对 DWG 原生格式支持有限新版本 DWGR2013 之后基本读不了只有 DXF 是公开格式。解决先把 DWG 批量转成 DXF 再喂给插件这是这类插件的通用前置步骤。我一般会直接让出图方另存一份 DXF 2007既避开版本问题又保留全部属性省得自己转。批量场景就把 DWG→DXF 转进批处理脚本里全程不用手动操作。凡是遇到读取失败先别怀疑插件坏了九成是文件格式和版本问题先确认扩展名和另存版本再排查代码。5. 进阶用法整目录批量转换与字段完整性自查5.1 整目录批量转换一条命令处理几百张图竣工图入库很少只转一张几百张是常态手工一张张敲命令不现实。插件支持目录模式python cad2shp.py --input-dir ./dxf_all/ --recursive --output ./shp_out/ -c attrib_map.json逻辑说明--input-dir 指定目录--recursive 递归子目录插件遍历目录下所有 .dxf 逐文件转换输出到 shp_out 平铺目录避免子目录结构影响 GIS 导入。参数说明输出目录同名文件会被覆盖建议每次转换前清空或换一个带时间戳的目录跑完终端会打印每张图的实体统计和跳过原因批量场景建议把输出重定向到日志文件事后再查有据可依。5.2 用配置模板固定业务字段批量场景最怕每张图字段不齐这张有井号那张没有。在 attrib_map.json 里把业务字段定死整个项目共用一套{ default_fields: [LAYER, HANDLE, ENT_TYPE, TEXT, ELEV], attr_map: { 井号: WELL_NO, 井底高程: EL_BOTTOM, 管径: DIAMETER, 材质: MATERIAL, 埋深: BURY_DEPTH }, strict: true }strict 设为 true 时插件遇到映射表里没有的属性标签会输出警告而不是静默丢弃方便你发现图纸里混进了意料之外的属性。第一次全量跑完统计日志里命中的属性标签集合把这个集合和映射表对比缺的补上多余的确认无用两三轮以后模板就稳定了。之后批量转换就是无脑跑重点放在结果自查上。5.3 转完自动自查字段完整性脚本我现在批量转换后不靠肉眼抽查直接跑一段自查脚本import glob, shapefile required {LAYER, HANDLE, WELL_NO, DIAMETER, TEXT} for shp_path in sorted(glob.glob(./shp_out/*.shp)): sf shapefile.Reader(shp_path) fields [f[0] for f in sf.fields[1:]] # 跳过 DeletionFlag missing required - set(fields) well_idx fields.index(WELL_NO) if WELL_NO in fields else -1 empty_count 0 if well_idx 0: # 统计 WELL_NO 为空字符串或空格的记录 empty_count sum(1 for rec in sf.records() if rec[well_idx] in (, )) status OK if not missing and empty_count 0 else CHECK print(f{shp_path}: {status} 缺字段{sorted(missing)} 井号空值{empty_count})逻辑说明required 是项目必填字段集合遍历输出目录所有 SHP检查字段是否齐全再统计 WELL_NO 空值数量。字段缺失或空值存在就把状态标成 CHECK。参数说明glob 按路径匹配sorted 保证输出顺序稳定方便对照日志排查well_idx 先判断字段存在再取下标避免字段缺失时 index() 抛异常。这段脚本建议存成 check.py 放项目根目录每次批量转完先跑它全 OK 再导 GIS比人工抽查快得多也不会漏掉几十张图里某一张的属性缺失。从那以后我每次做 CADSHAPE 带属性转换不管单张还是一百张都强制先跑一遍 check.py字段齐、空值少才往入库流程走。这个习惯帮我挡掉好几次深夜返工尤其是那种转完才发现井号全空的案例——查到最后往往只是某张图的属性标签多了一个空格映射没命中。先自查再入库是这类转换项目里性价比最高的一道保险。希望帮到你。本文还有配套的精品资源点击获取