Python 读写 DXF 实战:用 ezdxf 批量处理 CAD 图纸
简介ezdxf 是一个与 DXF 版本无关的 Python 程序包面向需要以编程方式创建、读取和修改 DXF 图纸的开发者尤其适合 CAD 二次开发、工程图纸自动化处理等场景。它支持 R12 至 R2018 各版本 DXF 的读写与新建能完整保留未知标签即使图纸包含第三方应用数据也可安全打开与保存且跨 Windows、Linux、macOS 平台兼容 CPython 与 pypy3。资源包共 1250 个文件约 20.12MB以 717 个 py 源码为主体辅以 rst 文档、png 示意图、dxf 示例图纸、ttf 字体及少量 pyx、pxd 等 Cython 扩展文件结构完整便于查阅源码与文档。目前已有 2418 人学习下载。借助该包读者可快速掌握 DXF 文件读写、实体创建与修改、版本兼容处理等核心用法并参考示例图纸与文档搭建自己的 CAD 自动化脚本是学习 Python 操作 DXF 的实用工具库。1. 用 Python 读写 DXF为什么我最后留了 ezdxf 在环境里如果你做过 CAD 相关的自动化大概率遇到过这种局面甲方丢来一堆 DXF 图纸要求批量改图层颜色、提取所有标注文字、或者把几千个图元按规则重新归类。手动开 CAD 点一整天不现实用别的库要么读不全、要么写出来的文件打不开。我最早用过一个只能读不能写的库改完还得回 CAD 里手动另存等于白干。后来换成 ezdxf才算把「读—改—写」这条链路跑通。ezdxf 是一个纯 Python 的 DXF 读写库不需要装 AutoCAD不依赖任何商业组件pip 装完就能用。它覆盖了从 R12 到 R2018 的 DXF 版本能操作图元、图层、块、标注、文字样式这些核心对象。适合谁做批量图纸处理的、搞 CAD 数据提取的、需要程序化生成图纸的以及想把 DXF 接进自己 Python 工具链的人。这篇不是 API 文档翻译是我自己踩过坑之后整理的一条可复现路径。2. 环境搭建与第一个可运行脚本从安装到读出图元2.1 安装与版本选择安装本身没什么好说的但版本选择有个坑值得先讲。ezdxf 的 API 在不同大版本之间有过调整尤其是add_text和add_mtext的参数、以及doc.header的访问方式。我一般会锁一个近期稳定版而不是无脑装最新。# 建议在虚拟环境里装避免和系统里的 CAD 相关包冲突 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 装 ezdxf锁一个稳定版本 pip install ezdxf1.1,2.0 # 验证安装 python -c import ezdxf; print(ezdxf.__version__)逻辑说明用虚拟环境隔离是基本操作重点在版本约束。1.1,2.0这个范围能避开早期 0.x 版本里一些已经废弃的接口又不会跳到还没稳定的 2.x。参数上如果你团队里有人用旧脚本先确认他们用的哪个版本再决定要不要统一。装完之后先别急着写复杂逻辑拿一个最小 DXF 跑通读取流程。如果没有现成文件ezdxf 可以自己创建一个。import ezdxf # 创建一个新的 DXF 文档版本用 R2010兼容性比较好 doc ezdxf.new(dxfversionR2010) # 新建一个图层颜色设为红色颜色号 1 doc.layers.add(nameMY_LAYER, color1) # 拿到模型空间往里加图元 msp doc.modelspace() msp.add_line((0, 0), (100, 0), dxfattribs{layer: MY_LAYER}) msp.add_circle((50, 50), radius25, dxfattribs{layer: MY_LAYER}) msp.add_text(测试文字, dxfattribs{height: 5, layer: MY_LAYER}).set_placement((10, 10)) # 保存 doc.saveas(demo_output.dxf) print(已生成 demo_output.dxf)逻辑说明ezdxf.new()的dxfversion参数决定输出文件的 DXF 版本R2010 是很多下游软件都能读的折中选项。doc.layers.add()里color1是 AutoCAD 颜色索引ACI1 代表红。dxfattribs这个字典是 ezdxf 里非常核心的一个参数几乎所有add_*方法都靠它来指定图层、颜色、线型等属性。set_placement是给文字定位的比直接传insert更直观。2.2 读取已有 DXF 并遍历图元生成只是热身实际工作里更多是读别人的文件。下面这段遍历所有图元、按类型统计并提取文字内容。import ezdxf from collections import Counter doc ezdxf.readfile(input.dxf) msp doc.modelspace() type_counter Counter() texts [] for entity in msp: dxftype entity.dxftype() type_counter[dxftype] 1 # 提取 TEXT 和 MTEXT 的文字内容 if dxftype TEXT: texts.append(entity.dxf.text) elif dxftype MTEXT: texts.append(entity.text) # MTEXT 用 .text 属性 print(图元类型统计, dict(type_counter)) print(提取到的文字条数, len(texts)) for t in texts[:10]: print(repr(t))逻辑说明ezdxf.readfile()会自动识别 DXF 版本。遍历msp得到的每个entity用dxftype()判断类型。注意 TEXT 和 MTEXT 取文字的方式不一样TEXT 用entity.dxf.textMTEXT 用entity.text这个差异我第一次写的时候搞混了结果 MTEXT 全取到空字符串。Counter用来快速统计图元构成排查文件里到底有什么东西时很好用。参数上readfile还有个encoding参数遇到中文乱码时可以显式指定但大多数情况让它自动检测就行。如果文件很大遍历时可以考虑用msp.query(TEXT MTEXT)只取需要的类型比全量遍历快。3. 图元操作与批量修改图层、文字、块的实际处理3.1 图层批量改名与颜色调整批量改图层是高频需求。比如甲方要求把所有以OLD_开头的图层统一改成NEW_前缀同时把颜色改成指定值。import ezdxf doc ezdxf.readfile(input.dxf) # 遍历所有图层按规则改名和改色 rename_map {} for layer in doc.layers: old_name layer.dxf.name if old_name.startswith(OLD_): new_name NEW_ old_name[4:] rename_map[old_name] new_name layer.dxf.name new_name layer.dxf.color 3 # 绿色 # 关键一步图元上引用的图层名也要同步更新 for entity in doc.modelspace(): layer_name entity.dxf.get(layer, None) if layer_name in rename_map: entity.dxf.layer rename_map[layer_name] doc.saveas(output_renamed.dxf) print(改名映射, rename_map)逻辑说明这里有个容易翻车的地方——改了doc.layers里的图层名并不自动更新图元上引用的图层名。图元通过dxf.layer存的是图层名字符串不是对象引用。所以必须再遍历一遍图元把旧名字替换成新名字。我第一次只改了图层表结果打开文件发现图元全跑到默认图层 0 上去了血泪经验。参数上layer.dxf.color用的是 ACI 颜色号常见值1 红、2 黄、3 绿、4 青、5 蓝、6 品红、7 白/黑。如果要真彩色得用layer.rgb属性但兼容性不如 ACI。3.2 文字内容批量替换与块内图元处理文字替换看起来简单但块BLOCK里的文字是另一个坑。块定义里的图元不在模型空间直接遍历到得单独处理。import ezdxf doc ezdxf.readfile(input.dxf) def replace_text_in_entities(entities, old, new): 在给定图元集合里替换文字内容 count 0 for e in entities: if e.dxftype() TEXT: if old in e.dxf.text: e.dxf.text e.dxf.text.replace(old, new) count 1 elif e.dxftype() MTEXT: if old in e.text: e.text e.text.replace(old, new) count 1 return count # 1. 处理模型空间 n1 replace_text_in_entities(doc.modelspace(), 旧项目名, 新项目名) # 2. 处理所有块定义内部的图元 n2 0 for block in doc.blocks: n2 replace_text_in_entities(block, 旧项目名, 新项目名) # 3. 处理布局图纸空间 n3 0 for layout in doc.layouts: n3 replace_text_in_entities(layout, 旧项目名, 新项目名) doc.saveas(output_replaced.dxf) print(f模型空间替换 {n1} 处块内替换 {n2} 处布局替换 {n3} 处)逻辑说明doc.blocks遍历的是所有块定义块定义本身也是可迭代的图元集合。doc.layouts包含模型空间和各个图纸空间布局。三处都处理完才算干净。很多人只处理模型空间结果图纸边框里的标题栏文字没换掉交付时被退回来。参数上替换逻辑用的是 Python 字符串的replace区分大小写。如果要不区分大小写得先lower()比较再处理但那样会丢失原始大小写需要额外记录。块内文字如果属性是ATTRIB块属性处理方式又不一样得用entity.dxf.tag和entity.dxf.text配合这个后面进阶部分再说。4. 避坑与排查那些让我重跑脚本的瞬间4.1 中文乱码现象是文字变成问号或方块现象读进来的中文文字显示为???或者乱码方块。原因DXF 文件的编码声明和实际内容不一致早期 R12 版本尤其常见有些文件头写的是 ANSI 但内容实际是 GBK。解决ezdxf.readfile()加encoding参数显式指定比如encodinggbk。如果还不确定先用二进制方式读文件头几行看$DWGCODEPAGE的值。4.2 保存后文件打不开现象是 CAD 提示文件损坏现象脚本跑完没报错但用 CAD 打开提示文件损坏或版本不兼容。原因多半是dxfversion设得太老或太新或者写入了一些该版本不支持的图元属性。解决统一用R2010或R2013这两个版本兼容性最稳。如果必须输出 R12注意 R12 不支持 MTEXT、LWPOLYLINE 等图元得先转换。4.3 图元丢失现象是遍历数量对不上现象明明文件里有很多图元遍历modelspace()却只拿到一部分。原因图元可能在块定义里、在图纸空间布局里或者被放在了paperspace而不是modelspace。解决分别遍历doc.blocks、doc.layouts用Counter统计各处的图元数量定位到底在哪。另外msp.query()支持按类型过滤比手动判断更可靠。4.4 性能问题现象是处理大文件时内存暴涨现象处理几万个图元的 DXF 时内存占用飙升甚至卡死。原因一次性把所有图元读进列表或者频繁saveas。解决用生成器方式遍历不要list(msp)批量修改完再统一保存一次不要每改一个图元存一次。如果文件特别大可以考虑用ezdxf.addons里的drawing模块做流式处理。4.5 块属性取不到现象是 ATTRIB 文字为空现象块参照里的属性文字用普通 TEXT 方式取不到。原因块属性是ATTRIB类型挂在INSERT图元下面不是独立的 TEXT。解决先找到INSERT图元再遍历它的attribs用attrib.dxf.text取值。如果要改改完还得调attrib.dxf.text new_value并且确保块定义里有对应的ATTDEF。5. 进阶技巧块属性操作与 DXF 版本转换的验证方法块属性这块值得单独拎出来讲因为它是自动化改图纸标题栏的核心。假设你有一个带标题栏的图框块里面有「项目名称」「图号」「日期」几个属性要批量替换。import ezdxf doc ezdxf.readfile(input.dxf) msp doc.modelspace() # 找到所有块参照INSERT按块名筛选 target_block_name TITLE_BLOCK updated 0 for insert in msp.query(fINSERT[name{target_block_name}]): for attrib in insert.attribs: tag attrib.dxf.tag if tag PROJECT_NAME: attrib.dxf.text 新项目名称 updated 1 elif tag DRAWING_NO: attrib.dxf.text DWG-2024-001 updated 1 doc.saveas(output_titleblock.dxf) print(f更新了 {updated} 个属性)逻辑说明msp.query(INSERT[nameTITLE_BLOCK])是 ezdxf 的查询语法按图元类型和属性过滤比手动遍历快也准。insert.attribs拿到的是该块参照的所有属性每个attrib有dxf.tag属性标签和dxf.text属性值。改完直接保存即可不需要额外同步块定义因为属性值是存在块参照上的。参数上查询语法里的name是块名区分大小写。如果块名不确定可以先遍历所有 INSERT打印insert.dxf.name看看。版本转换的验证方法转换完不要只看脚本有没有报错要实际验证。我一般会做三步——第一步用 ezdxf 重新读一遍输出文件确认图元数量和类型统计和预期一致第二步用doc.dxfversion确认版本号第三步如果条件允许用目标 CAD 软件实际打开一次看有没有警告。import ezdxf # 验证输出文件 doc ezdxf.readfile(output_titleblock.dxf) print(DXF 版本, doc.dxfversion) print(图层数, len(doc.layers)) print(块定义数, len(doc.blocks)) msp doc.modelspace() from collections import Counter counter Counter(e.dxftype() for e in msp) print(模型空间图元统计, dict(counter)) # 检查是否有图元落在不存在的图层上 layer_names {layer.dxf.name for layer in doc.layers} orphans [e.dxf.layer for e in msp if e.dxf.get(layer) and e.dxf.layer not in layer_names] print(孤立图层引用, set(orphans) if orphans else 无)逻辑说明这段验证脚本是我每次批量处理完都会跑的。doc.dxfversion确认版本Counter确认图元构成最后那个孤立图层检查能发现「图元引用了不存在的图层」这种隐蔽问题——这种文件在 CAD 里打开可能不报错但图元显示会异常。从那以后我每次批量改完 DXF都强制走一遍「重读—统计—孤立图层检查」这三步宁可多花三十秒也不想交付后被退回来重跑。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

MES/ERP复杂页面组件化设计:从业务拆解到落地实践

MES/ERP复杂页面组件化设计:从业务拆解到落地实践

做MES/ERP实施和开发这些年,我见过最多的场景就是:业务方提了一个需求,说“就要一个生产工单页面”,结果打开原型一看,字段几十个、页签七八个、表格套表格、树里嵌表单,一个页面顶别的系统三个页面。真正动…

2026/10/13 16:27:42 阅读更多 →
Qt 3D散点图实战:从压缩包到实时数据流与性能调优

Qt 3D散点图实战:从压缩包到实时数据流与性能调优

简介:这份资源面向具备一定 Qt 与 C 基础、希望入门三维数据可视化的开发者,围绕 Qt 3D 模块中的散点图实现展开。包内示例演示了如何以 QEntity 作为场景根节点,通过 QScatter3DSeries 与 QScatter3DData 组织并渲染三维数据点,同…

2026/10/13 16:27:42 阅读更多 →
数字信号处理与MATLAB实现:采样、频谱分析和滤波器设计

数字信号处理与MATLAB实现:采样、频谱分析和滤波器设计

做数字信号处理(DSP)的这批人,MATLAB基本就是日常吃饭的家伙。不管是刚入门的本科生、做项目的研究生,还是已经工作在算法岗位的工程师,只要涉及到信号采集、频谱分析、滤波器设计这类活儿,十有八九都会打开…

2026/10/13 16:26:41 阅读更多 →

最新新闻

PS5串流实战指南:从局域网到外网的远程游戏配置与延迟优化

PS5串流实战指南:从局域网到外网的远程游戏配置与延迟优化

直接接PS5玩家一个很现实的问题:这台机器买回来之后,是不是基本就长在客厅电视柜上了?客厅被占、卧室想玩、出差想刷两把,每次都只能乖乖回到电视前。我捣鼓AnyPS5这套串流方案,就是为了把这台主机从HDMI线的长度里解放…

2026/10/13 20:09:06 阅读更多 →
若依vue3前端页面框架:路由联动、权限指令与缓存机制解析

若依vue3前端页面框架:路由联动、权限指令与缓存机制解析

简介:若依vue3前端页面框架是一套基于Vue3与Element Plus的开源后台管理前端解决方案,面向需要快速搭建企业级系统的开发团队及初中级前端工程师,适用于中后台管理系统、权限控制界面、数据看板等典型场景。压缩包共299个文件、约3MB&#xf…

2026/10/13 20:09:06 阅读更多 →
嵌入式视觉系统中MT9M001C到LCD的端到端时序设计

嵌入式视觉系统中MT9M001C到LCD的端到端时序设计

简介:本资源是面向FPGA初学者与嵌入式图像处理学习者的实战项目,聚焦于MT9M001 CMOS图像传感器的驱动与实时显示实现,适用于基于Altera/Intel FPGA平台的开发板验证与课程实验。项目完整呈现了从传感器数据采集、FPGA逻辑控制(含时…

2026/10/13 20:09:06 阅读更多 →
PS5全机型优化指南:从版本识别、M.2扩展到HDMI 2.1设置与故障排查

PS5全机型优化指南:从版本识别、M.2扩展到HDMI 2.1设置与故障排查

如果你手头有一台 PS5,或者正打算入手,不管是初版、轻薄版还是 Pro 版,这篇文章都是给你准备的。我写这个东西的起因很简单:群里隔三差五就有人问"我这个 PS5 为什么风扇声音这么大""到底要不要上 Pro""…

2026/10/13 20:09:06 阅读更多 →
STM32跑马灯实验详解:从时钟配置到GPIO驱动与工程下载

STM32跑马灯实验详解:从时钟配置到GPIO驱动与工程下载

简介:这份资源是面向嵌入式初学者与STM32入门者的跑马灯实验例程包,围绕GPIO输出控制这一核心知识点,帮助读者快速上手STM32微控制器的基本开发流程。资源以ALIENTEK MINISTM32开发板为硬件平台,配套完整工程代码与详细注释&#…

2026/10/13 20:09:06 阅读更多 →
Steinberg VST插件开发包入门:从零构建VST3音频插件

Steinberg VST插件开发包入门:从零构建VST3音频插件

简介:Steinberg VST插件开发包(VST3 SDK 3.5版)面向音频插件开发者、音乐软件工程师及数字音频工作站扩展爱好者,提供创建虚拟乐器与音频效果处理器所需的完整开发环境。包内共5764个文件,以html文档、png界面素材、h头…

2026/10/13 20:08:06 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →