做图纸管理系统、算量工具、审图平台的人,几乎都会在某个节点撞上同一堵墙:甲方扔过来一个压缩包,里面三百个 DWG 文件,版本从 R14 横跨到最新格式,还夹着一堆外部参照、自定义实体和缺字体的文字样式。这时候“DWG 数据交换方案选型”就不是一道纯技术题,而是一道会持续两三年的成本题——选错了,后面每一次格式升级、每一个新客户、每一批奇奇怪怪的图纸,都得重新填一遍坑。
我前后参与过几套图纸解析链路的搭建,有踩在宿主软件自动化接口上的,有啃商业内核 SDK 的,也有图便宜上开源解析库、最后被代理实体逼到重写的。下面把这几年攒下来的判断依据、参数细节和踩坑记录整理一遍,尽量说人话,也尽量说透“为什么这么选”。
这篇文章适合谁看:正在做图纸管理、模型轻量化、算量、审图、加工排产这类系统,需要读写 DWG 的架构师和后端开发;也适合被“能不能直接打开 DWG 文件”这个问题卡住的产品经理。看完你至少能判断出自己该走哪条路,以及那条路上大概会摔几跤。
1. 先把“数据交换”这件事说清楚
1.1 DWG 不是“一个文件”,而是一套带版本的系统
很多人把 DWG 当成类似 PDF 的静态文档,这是所有踩坑的起点。DWG 本质是一个带版本分支的二进制容器,文件头前六个字节就是版本标识,业内叫魔数(magic number)。读文件的第一步永远是读这六个字节,然后决定用哪条解析路径。
常见的版本对照长这样:
| 版本叫法 | 文件头魔数 | 关键结构变化 |
|---|---|---|
| R14 | AC1014 | 结构相对简单,很多老库只完整支持到这一代 |
| 2000 / 2000i | AC1015 | 引入更完整的对象模型 |
| 2004 / 2005 / 2006 | AC1018 | 改为自定义压缩,随机访问结构变化 |
| 2007 / 2008 / 2009 | AC1021 | 字符串改统一编码,压缩方式再次调整 |
| 2010 / 2011 / 2012 | AC1024 | 增加新的实体与属性类型 |
| 2013 至 2017 | AC1027 | 结构微调,兼容性要求更高 |
| 2018 及以后 | AC1032 | 目前主流方案普遍支持的上限 |
这张表是选型的第一道门槛。任何方案你都得先问一句:它支持到哪个魔数。看起来只是版本号,实际上是两套完全不同的读写引擎——2004 之后的压缩方式和 2004 之前差异极大,一个只支持到 R14 的库拿到 2018 文件,轻则报错,重则读出乱码坐标,比直接失败更麻烦。
1.2 三个真实业务场景,决定了三种完全不同的选型
我在做技术评审时最怕听到的一句话是“我们要支持 DWG”。这句话没有信息量,必须拆成具体动作。
场景一:只读轻量化预览。Web 端看图、手机端查图、移动巡检。这类需求只要求“看得见、看得清、能缩放”,不要求图层语义完整。选型上应该走“转换 + 矢量切片”路线,把 DWG 在服务端转成中间格式,前端只负责渲染。这时候你根本不需要一个完整的 DWG 读写内核。
场景二:读写编辑。加批注、改图层颜色、插入图块、批量替换标题栏,甚至要把修改结果另存为新的 DWG 交还给设计方。这就是硬门槛了——写入的保真度要求极高,一旦写出来的文件对方打不开或者丢失了自定义对象,整个项目就废了。这类需求基本只能在商业内核 SDK 或宿主软件自动化之间二选一。
场景三:数据提取。算量、材料清单、设备表、图框信息抽取、图层统计。这类需求是“读而不写”,但要求语义准确——文字内容、块属性、扩展数据、多段线顶点坐标都得对。开源方案在这里勉强能用,前提是你能接受部分实体读不出来。
1.3 选型前必须问自己的五个问题
在翻任何厂商文档之前,先把这五个问题在白板上写下来,答案会直接把选项砍掉一半:
- 要不要写?只读和读写的成本差距通常是三到五倍,不是一点半点。
- 要保真到什么程度?是“人能看懂”还是“设计软件打开后逐字节一致”?后者只有原厂级方案能承诺。
- 版本覆盖到哪一代?只支持 2018 以后,还是必须兼容十年前的存量图纸?存量图纸往往是甲方最在意的。
- 单文件多大、并发多高?一个 300MB 的总图和一个 2MB 的单体图,是完全不同的工程量。
- 预算形态是什么?一次性买断、按年订阅、按调用量计费,这三种对产品的定价模型影响极大。
我在一个项目里就吃过没问第四个问题的亏:内部测试全用几兆的小图,性能漂亮得很,上线后客户上传的第一批就是几十兆的总平面图,内存直接打满,服务雪崩。
2. 五类主流方案的全景拆解
2.1 方案A:宿主软件自动化接口
思路很直接:服务器上装一套正版桌面 CAD 软件,通过 COM/ActiveX 组件、命令行脚本或者批处理脚本去驱动它,让软件自己打开、修改、另存。
优势是保真度天花板。因为它就是原厂引擎本身,任何自定义对象、任何代理实体、任何奇葩的字体和线型,它都能处理。你不需要理解 DWG 的内部结构,只需要会调用对象模型。
劣势在于工程性极差。它是单进程的、有界面的、会弹对话框的、会崩溃的。放到服务端高并发场景里,基本等于给自己埋雷。我见过最典型的做法是:起一个进程池,每个转换任务分配一个独立进程,超时就杀掉重建,外面套一层看门狗。这套东西能跑,但运维成本高得离谱——机器上必须装图形环境,用户会话不能随便登出,杀毒软件还可能误杀子进程。
还有一个容易被忽略的点:版本绑定。宿主软件大版本升级后,部分接口行为会变,你的脚本可能一夜之间全挂。授权也是按席位算的,横向扩容时账单一目了然。
我的判断是:内部工具、低频批处理、对保真度有极端要求的离线任务,这个方案值得考虑;面向公网的高并发服务,尽量别选。
2.2 方案B:商业 DWG 内核 SDK
业内有一家专门做 CAD 互操作的非营利组织提供跨平台内核,另外原厂也提供官方的读写组件。这类方案的定位是:不依赖宿主软件,直接在代码里读写 DWG,支持 Windows / Linux / macOS,提供 C++ 主接口和多语言绑定。
它的核心价值在于保真度和可控性的平衡。它不需要图形界面,能跑在容器里,能多线程调用(注意:多数内核的单个文档对象不是线程安全的,要按文档维度隔离),能处理大部分自定义对象和代理实体的“只读保留”。
选型时要重点确认几件事:
- 支持的最高魔数版本,以及新版本发布后的跟进周期。
- 是否有“部分编辑”能力,比如只改图层属性而不重写整个文件。
- 授权模型的颗粒度,是按开发者席位、按部署服务器、还是按年订阅。
- 二进制体积和运行时依赖,有些内核包体很大,塞进镜像会让部署变慢。
坦白说,如果项目是长期的、要写入的、对保真度有要求的,商业内核基本是唯一稳妥解。它的钱花在明处,比后期拿人力去填兼容性的坑划算得多。
2.3 方案C:开源解析与转换库
开源生态里有两类:一类专门读 DXF(文本格式,本质是 DWG 的兄弟格式),一类尝试直接啃 DWG 二进制。
DXF 这条路相对成熟,很多库能完整解析实体、图层、块表,做数据提取完全够用。前提是上游能把 DWG 转成 DXF——而这个转换本身又需要工具,绕回来了。
直接解析 DWG 的开源库,普遍问题是覆盖不全。常见的表现是:简单图形正常,一碰到代理实体、自定义对象、新版本特性就抛异常或者静默跳过。更隐蔽的是静默跳过——你以为读成功了,其实少了半张图,等到客户投诉才发现。
开源方案真正合适的定位是:格式嗅探、快速原型、内部数据清洗、非核心链路。比如先用它读文件头判断版本,再决定分发给哪个引擎;或者用它做图层名的快速统计。把它放在主链路上,需要很强的兜底能力。
2.4 方案D:中间格式中转
下游只要有视觉结果,不需要精确数据,那中间格式是好选择:
- 转 DXF:保留图层和实体语义,但体积膨胀,超大图转换慢。
- 转 PDF:适合出图打印,但图层语义基本丢了,做不了数据提取。
- 转 SVG:适合 Web 渲染,同样丢语义,且超大图元数量会让浏览器卡死。
- 转位图或瓦片:预览体验最好,代价是彻底放弃矢量精度。
这条路的精髓是“按需降级”。如果你的产品 90% 的用户只需要看图,只有 10% 需要取数,那就把两条路分开做,别让 90% 的人为 10% 的需求买单。
2.5 方案E:转换服务与外部集成
不自建能力,直接对接第三方转换服务。优点是不用养团队、不用买授权、上线快。缺点同样明显:
- 数据边界问题。图纸对很多客户来说是核心资产,传出自己的环境要过合规评审,这一关往往比技术难。
- 限流与成本线性增长。调用量一上来,账单跟着涨,而且很难做缓存优化。
- 能力天花板。对方不支持的特性,你也没有办法补。
我的经验是:这类方案适合做过渡期方案或者长尾兜底。比如自建引擎覆盖 95% 的常规文件,剩下 5% 的疑难杂症走外部服务,成本可控,风险也可控。
3. 选型决策矩阵:把主观感觉变成可打分的表格
3.1 六个核心评估维度与权重
选型讨论最容易变成“我觉得”。我的做法是把它变成打分表,先定维度,再定权重,最后各方案独立打分。下面这套权重是我在“读写混合、中高并发、面向外部客户”的项目里用的,你可以按自己情况调。
| 维度 | 说明 | 建议权重 |
|---|---|---|
| 保真度 | 读写后文件是否可被原软件无损打开 | 25% |
| 版本覆盖 | 支持的最低到最高魔数范围 | 20% |
| 并发与稳定性 | 能否容器化、多进程、长时间跑不崩 | 20% |
| 总拥有成本 | 授权 + 服务器 + 人力 + 运维 | 15% |
| 数据边界 | 文件是否需要离开自有环境 | 10% |
| 维护成本 | 升级跟进、问题排查难度 | 10% |
按这套权重打分,纯只读预览场景下,开源 + 中间格式的组合往往能拿高分;而读写编辑场景下,商业内核会明显领先,宿主软件自动化因为并发项拿低分被拉下来。
3.2 按场景直接给结论
如果不想算分,可以直接对照:
| 你的场景 | 首推方案 | 备选 | 尽量避免 |
|---|---|---|---|
| Web 只读预览 | 服务端转中间格式 + 前端渲染 | 转瓦片 | 直接前端解析 |
| 数据提取 / 算量 | 商业内核只读模式 | DXF 中转 + 成熟解析库 | 直接啃二进制的开源库 |
| 读 + 写 + 回传 | 商业内核 SDK | 宿主软件自动化(内网) | 开源方案 |
| 小批量离线批处理 | 宿主软件自动化 | 商业内核 | 自研解析 |
| 快速验证 / Demo | 开源解析库 | 外部服务 | 提前买大授权 |
3.3 成本模型:算一笔三年的账
很多团队只算授权费,不算人力和服务器,最后发现“省钱方案”更贵。我做过一次粗算,假设一个中等规模的图纸服务,日均处理两万个文件,三年周期:
| 项目 | 自研开源路线 | 商业内核路线 | 外部服务路线 |
|---|---|---|---|
| 授权/调用费 | 0 | 中高(一次性或年费) | 按量,随规模线性涨 |
| 研发人力 | 高(兼容性攻坚 2 至 3 人月起步) | 中(集成 1 人月) | 低(对接 0.5 人月) |
| 运维与排障 | 高(长尾问题无底洞) | 低 | 中(受制于人) |
| 三年总成本趋势 | 前期低,后期持续投入 | 前期高,后期平稳 | 全程线性增长 |
结论很直白:开源的“免费”是把授权费换成了人力费,而且这笔人力费没有上限。如果团队规模小、工期紧,商业内核反而是省钱的选择。
4. 关键技术细节:那些决定成败的坑点
4.1 版本魔数与文件结构
前面说过要先读文件头。实际工程里还要多做一步:版本白名单管理。不要用“try 一下失败就回退”的方式,因为部分旧库遇到新版本文件不会报错,而是按旧结构硬解,结果是坐标全错、实体错位。
正确做法是维护一张映射表,读出来的魔数不在表里就直接拒绝,给用户明确的错误提示,让他另存为低版本。这句提示看着不优雅,但比输出一张错图强一万倍。
另外要留意分页与随机访问的变化。2004 之后的版本为了支持大文件,引入了更复杂的段表和压缩,读取时不能顺序扫,必须按段索引跳转。这也是为什么很多“暴力扫描”式的开源实现性能极差。
4.2 实体、块表与扩展数据的读取顺序
DWG 的内部组织大致是:文件头 → 各类段表 → 块表 → 实体段。顺序不能乱,因为实体里引用了块表的索引,块表里又引用了线型和图层。
工程上我建议分两遍走:第一遍只建索引(图层、块定义、线型、字体、样式),第二遍再展开实体。这样做的直接好处是,遇到块参照时可以按需递归,而不是读到一个就现查一次表,性能差别在复杂图纸上非常明显。
块参照的递归要注意两点:嵌套深度上限和循环引用检测。我见过一张图里 A 块引用 B 块、B 块又引用 A 块,解析器直接栈溢出。加一个深度计数器和一个已访问集合,几行代码的事,能救命。
扩展数据(XData)和块属性是数据提取的重灾区。很多图纸把关键信息塞在扩展数据里,图层名干干净净,你只看实体属性什么都拿不到。选型时一定要测这个:拿一张带扩展数据的真实图纸,看方案能不能读出来。
4.3 字体、线型、外部参照与光栅
字体问题是我遇到频率最高的投诉来源。DWG 里的文字用的是形文件字体(SHX),这是二进制形状定义,本质上没法直接转成通用字体。缺字体时的表现是:文字位置偏移、字宽不对、干脆不显示。
处理思路有三条,可以叠加用:
- 建字体映射表,把常见的形文件字体映射到系统里的等价字体,宁可字形略有差异,也要保证位置和宽度接近。
- 兜底用通用字体,并统一字号计算方式,避免整张图排版崩掉。
- 保留原始字体文件,如果客户能提供,优先用原字体,效果最好。
外部参照(Xref)是另一个坑。参照的图纸不在包里,主图就是残缺的。解析时要能识别出“这里有参照但缺文件”,并在结果里标记出来,而不是默默画一半。光栅图嵌入和 OLE 对象同理,能识别、能占位,就算合格。
4.4 代理实体与自定义对象
这是所有方案的分水岭。某些专业软件会在标准 DWG 里写入自己定义的私有对象,在没有对应软件的环境下,这些对象会退化成“代理实体”——只有一个外壳和一段原始数据,语义丢失。
不同方案的表现差异极大:
- 宿主软件自动化:装了对应软件就能完整解开,这是它唯一的、也是最大的优势。
- 商业内核:多数情况能保留原始数据并在写回时原样带回,但渲染时需要降级显示。
- 开源库:大概率直接跳过或者报错。
选型时一定要拿一张带代理实体的真实图纸做验证,不要用自己画的测试图。这一条能帮你省掉后面几个月的返工。
4.5 坐标系统与单位
单位问题很隐蔽。文件里有单位设置,但很多图纸根本不填,或者填了和实际绘制不一致。工程上的做法是:不信任文件里的单位,用包围盒尺寸做合理性推断。一张标注为毫米的图,包围盒跨度几百万,那基本就是测绘坐标系。
超大坐标是另一个坑。有些图纸用了大地坐标,数值动辄上千万,单精度浮点根本存不下,转成渲染坐标时会出现明显抖动和精度丢失。解决办法是在解析阶段就做局部坐标平移,把图元整体平移到原点附近,只保留一个偏移量用于回算。
5. 一次完整的落地实操
5.1 服务分层设计
不管选哪种引擎,服务端结构我建议都按这个分层来,换引擎时只动中间一层:
| 层级 | 职责 | 关键点 |
|---|---|---|
| 接入层 | 上传、鉴权、限流 | 文件落临时区,不要进内存 |
| 嗅探层 | 读魔数、判断版本、算哈希 | 哈希做去重和缓存键 |
| 路由层 | 按版本和场景分发到不同引擎 | 支持降级和兜底 |
| 解析层 | 真正的读写与提取 | 进程隔离,独立超时 |
| 输出层 | 生成中间结果并落盘 | 结构化 JSON + 渲染数据 |
| 缓存层 | 结果缓存与二次访问 | 按内容哈希,不按文件名 |
这套分层的价值在于:嗅探层和路由层让多引擎共存成为可能。常规文件走主引擎,疑难文件路由到备选引擎,长期跑下来你会发现主引擎的覆盖率一路上升,因为你能清楚看到失败样本长什么样。
5.2 解析核心骨架与参数
下面这段是 Python 伪代码,把关键控制点标出来了,具体接口按你选的引擎替换:
import hashlib import os MAX_DEPTH = 12 # 块参照最大递归深度 MAX_FILE_MB = 500 # 单文件大小上限 TIMEOUT_SEC = 120 # 单文件解析超时 def sniff_version(path): with open(path, 'rb') as f: head = f.read(6).decode('ascii', errors='ignore') return head # 例如 AC1032 def build_cache_key(path): h = hashlib.sha256() with open(path, 'rb') as f: for chunk in iter(lambda: f.read(1 << 20), b''): h.update(chunk) return h.hexdigest() def parse_drawing(path, engine): size_mb = os.path.getsize(path) / 1024 / 1024 if size_mb > MAX_FILE_MB: raise ValueError('file too large: %.1fMB' % size_mb) version = sniff_version(path) if version not in engine.supported_versions: raise ValueError('unsupported version: %s' % version) doc = engine.open(path) # 第一遍:只建索引 index = engine.build_index(doc) entities = [] # 第二遍:展开实体 for e in engine.iter_entities(doc): if e.type == 'INSERT': entities.extend(expand_block(e, index, depth=0)) else: entities.append(engine.to_dict(e)) return { 'version': version, 'bbox': engine.bounding_box(doc), 'units': engine.guess_units(doc), # 推断而非直接信任 'entities': entities, } def expand_block(insert, index, depth): if depth > MAX_DEPTH: return [] # 超深就截断,不抛异常 block = index.get(insert.block_name) if block is None or block.name in insert.visited: return [] # 循环引用保护 insert.visited.add(block.name) out = [] for e in block.entities: if e.type == 'INSERT': out.extend(expand_block(e, index, depth + 1)) else: out.append(apply_transform(e, insert.transform)) return out几个参数值得单独说明。MAX_DEPTH设 12 是我实测下来的经验值:正常图纸的块嵌套很少超过五六层,设太高只会让异常文件吃光内存。MAX_FILE_MB设 500 是给正常业务留足余量,超过这个数的文件基本是拼图式的超大地形图,转成预览毫无意义,直接走离线任务更合适。TIMEOUT_SEC要按文件大小分档,我一般用 30 秒加每 10MB 加 20 秒的线性公式。
5.3 并发、内存与超时控制
这三个是一体的。经验数据:解析过程中的峰值内存一般是文件体积的 8 到 15 倍。一个 50MB 的图,峰值可能吃掉 700MB。所以按文件大小预估内存并做准入控制,比单纯限并发数更有效。
并发数不要按 CPU 核数设,按“核数 × 1.5”设比较合理,因为解析过程中有大量 I/O 和等待。同时一定要按进程隔离,不要把多个文件塞进同一个进程池里跑,一个异常文件就能把整个池子拖死。
超时策略我习惯分三档:小于 10MB 给 30 秒,10 到 100MB 给 90 秒,超过 100MB 走异步队列,不占用实时接口。这套分档上线后,超时报警量直接降了一个数量级。
5.4 结果校验与回归测试集
这是最容易被跳过、但最值钱的一步。我建议维护一个不少于 20 个文件的样本库,覆盖:
- 每个魔数版本各一个
- 带外部参照的
- 带代理实体或自定义对象的
- 带扩展数据属性的
- 超大坐标的
- 缺字体的
- 块嵌套很深的
- 明显有问题的(空文件、截断文件、改过后缀的)
每次换引擎或升级版本,跑一遍这个库,输出比对包围盒、实体数量、图层列表、关键文字内容。不要比对渲染截图,人眼看不出细粒度差异,数字能。
6. 常见问题速查与排查实录
6.1 典型故障表
| 现象 | 可能原因 | 排查动作 | 处理办法 |
|---|---|---|---|
| 坐标整体偏移 | 单位推断错误或大地坐标未平移 | 打印包围盒数值 | 加平移量,用包围盒反推单位 |
| 文字错位或消失 | 形文件字体缺失 | 检查字体引用列表 | 建映射表 + 通用字体兜底 |
| 少了一半图形 | 外部参照缺失或被静默跳过 | 检查参照标记 | 显式报缺,不静默 |
| 特定图元读不出 | 代理实体或自定义对象 | 对比原软件打开结果 | 换引擎或做降级占位 |
| 大文件服务崩溃 | 峰值内存超限 | 监控单任务内存曲线 | 按体积准入 + 异步队列 |
| 写回后对方打不开 | 保真度不足或版本不匹配 | 用原软件打开验证 | 换写入引擎,别硬扛 |
| 同一文件多次结果不同 | 缓存键用了文件名 | 检查缓存键生成 | 改用内容哈希 |
6.2 排查方法论:二分与最小复现
DWG 的问题排查,最有效的手段是二分删减。拿一张出问题的图,删掉一半图元,看还复现不;复现就再删一半,直到定位到那几个具体实体。听起来笨,但比对着代码猜快得多。我最快的一次是十分钟定位到一个特定的自定义标注对象。
第二步是最小复现。定位到实体后,新建一个空文件,只放这一个实体,如果能复现,就把它固定成回归样本。这个习惯坚持下来,你的样本库会变成团队最值钱的资产。
第三步是格式嗅探先行。任何异常,先看文件头魔数对不对、文件大小和实际内容是否匹配。有些文件是别人改了后缀名的,比如把 PDF 改成 DWG,你解析器报一堆错,其实压根不是格式问题。
6.3 我踩过的几个坑
第一个坑是静默跳过。早期用的一个开源解析库,遇到不认识的实体不报错,直接略过。测试阶段没人发现,上线后客户说“你们系统里这张图的设备表少了三行”,查了两天才明白是块属性没读出来。从那以后我给所有解析流程加了“实体计数比对”:解析出的实体数和引擎报告的总数必须一致,不一致就打警告日志。
第二个坑是用文件名做缓存键。客户更新图纸时习惯同名覆盖,结果系统一直返回旧结果,反馈“你们不刷新”。改成内容哈希后彻底解决,还顺带做了跨用户去重,缓存命中率反而涨了。
第三个坑是低估了字体问题的影响面。最初以为只是显示难看,后来发现文字宽度变化会导致整张图的排版和标注位置全乱,直接影响算量取数的准确性。现在字体映射是必做项,不是可选项。
7. 许可、合规与长期维护
7.1 许可证模式的三种类型
商业方案的授权大致分三种,选之前一定要和采购、法务一起确认:
- 按开发者席位:买几个名额给几个工程师用,适合团队小、部署环境多的场景。
- 按部署服务器:按机器或容器实例计数,横向扩容时要提前算好。
- 按年订阅:每年续费,升级包含在内,适合长期演进的产品。
最容易出问题的是“开发测试环境要不要授权”这个细节。有些授权模式对非生产环境有特殊条款,一定要在签约前问清楚,否则测试环境一扩容就踩线。
7.2 版本升级的兼容策略
DWG 格式不会停,方案也不能一劳永逸。我的做法是版本能力分级:
- 完整支持:当前主流版本,读写都保证。
- 只读支持:较新版本,先能读,写入等引擎跟进。
- 拒绝支持:超出能力范围的版本,明确提示用户另存。
这套分级要写进产品文档,也要体现在接口返回里。用户看到“当前版本仅支持读取”,比看到一张错图体验好得多。
另外要盯住引擎厂商的版本跟进周期。新格式发布后,各家跟进速度差别很大,如果你的客户群体里有大量用新版本的设计院,这个周期直接决定你的产品能不能接单。
7.3 上线后要盯的几个指标
- 解析成功率,按版本和文件大小分组看,别只看总数。
- 实体计数偏差率,解析数量与引擎报告数量不一致的比例,这是静默失败的唯一信号。
- 单任务峰值内存,用来校准准入阈值。
- P95 耗时,按体积分档看,均值没有意义。
- 缓存命中率,低说明键设计有问题或者文件更新频繁。
我个人的体会是,DWG 这个领域的选型没有“最优解”,只有“和你的场景匹配、并且你能承担其后果的解”。真正决定项目成败的往往不是选了什么引擎,而是你有没有把嗅探、路由、兜底、校验这四件事做扎实——引擎会换,这套骨架能一直用。
最后再分享一个实用的小技巧:任何新客户接入前,先要五张他们真实的图纸做样本,别用自己生成的测试文件。这五张图里大概率会藏着一个你从没见过的自定义对象,早知道比晚知道省太多事。