news 2026/10/14 16:38:00

Apache POI 实现 Word 转 HTML:doc/docx 解析、图片表格与批量转换实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache POI 实现 Word 转 HTML:doc/docx 解析、图片表格与批量转换实践

简介:面向 Java 后端与前端开发者的 Word 转 HTML 示例工程,基于 Apache POI 实现 doc、docx 及 WPS 文档的内容提取与网页展示,解决文档跨平台共享和在线预览需求。资源包共 131 个文件、约 726KB,内含 Java 源码、Spring Boot 启动类、XML 配置、Maven 构建文件及一个转换生成的 HTML 示例文件,并附带 JPEG 图片资源,便于直接导入开发工具运行调试。工程演示了通过 HWPFFactory 和 XWPFDocument 遍历段落、读取字体颜色等样式属性、提取图片并处理表格结构的完整流程,最终生成可在浏览器中直接查看的 HTML 页面;代码中同时考虑了 WPS 文档兼容性与图片二进制落地等细节,可作为文档转换服务的参考基线。已有 1365 人学习使用,适合需要快速掌握 POI 文档处理能力、或正在搭建办公文档在线预览功能的开发者参考。

1. Word 转 HTML:POI 提取文档内容的三个现实问题

接手过文档内容提取的人应该都遇到过这样的情况:需要把 Word 里的正文、图片、表格搬进网页前端展示,结果 doc 和 docx 一堆文件格式混杂,WPS 另存出来的文件还经常在样式上玩点花活。Word 转 HTML 看起来是件小事,真跑起来却会遇到编码、样式、图片路径三座山。这篇笔记想聊的是怎么用 Apache POI 把 doc/docx 里的内容提取出来,拼成一套可以直接交给前端渲染的 HTML 片段,把 WPS 兼容问题、图片内嵌、表格合并这类坑提前填平。适合正在做文档在线预览、知识库导入或数据迁移的开发者看。

2. Apache POI 双轨模型:doc 走 HWPF,docx 走 XWPF

2.1 底层封装差异决定了处理路线

POI 处理 Word 的逻辑是双轨制:老的 .doc 走 HWPF,新的 .docx 走 XWPF。这两个 API 不是同一个东西的升级版,而是针对两种完全不同的文件封装格式设计的两套接口。

.doc 是 OLE 复合文档格式,里面有一堆流(FileInformationBlock、WordDocument、Table 等),二进制组合很绕,POI 时至今日对 .doc 里的复杂排版还原度依然有限。.docx 本质是一个 ZIP 压缩包,里面是 word/document.xml、word/media/、word/header*.xml 这些 XML 文件,POI 解析的是 XML 树,做的是一层 Java 对象到 Office Open XML 的映射,可控性强得多。

所以接到需求时第一步不是写代码,而是先明确输入文件属于哪条路线。我的判断标准很简单:后缀是 .doc 就直接警告用户转换效果可能不完整,建议先转成 .docx;能拿到 .docx 就走 XWPF,把所有段落、表格、图片老老实实读出来。混着用 API 会直接编译报错,因为 HWPF 和 XWPF 连对象模型都不相通。

2.2 Maven 依赖与最小读取骨架

用 Maven 管理三个包,版本保持同一大版本就好。注意 poi-scratchpad 是读 .doc 的关键,只在 pom 里写 poi 和 poi-ooxml 是读不了 HWPF 的。

<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.x.x</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.x.x</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>5.x.x</version> </dependency>

版本号别用 4.x 的老坐标,新的 5.x 在包名 clean up 之后接口更统一,网上很多旧文章里的ooxml-schemas依赖已经不需要了。依赖配好后,先写一段验证文件能被正确解析的骨架代码:

try (InputStream in = new FileInputStream("sample.docx")) { XWPFDocument doc = new XWPFDocument(in); for (XWPFParagraph p : doc.getParagraphs()) { String text = p.getText(); if (text != null && !text.trim().isEmpty()) { System.out.println(text); } } }

这里用 try-with-resources 是必须的,XWPFDocument 持有底层的 OPCPackage,它内部关联一个 ZIP 文件句柄,不关闭会在 Windows 上留下文件锁,后续删除文件会一直失败。遍历 getParagraphs() 只拿到文档 body 直接子级的段落,表格里的内容不会出现在这个列表里,这是个容易忽略的边界。

同样思路处理 .doc 时,可以直接用 WordExtractor 提取纯文本:

try (InputStream in = new FileInputStream("sample.doc")) { WordExtractor extractor = new WordExtractor(in); String[] paragraphs = extractor.getParagraphText(); for (String text : paragraphs) { System.out.println(text); } }

WordExtractor 的好处是快速拿到文本内容,但它对字体、颜色、图片的还原能力很弱,HWPF 的模型加载某些 WPS 生成的 .doc 还会直接抛异常。所以我在项目里对 .doc 的定位是“能提文本就不错了”,要完整转 HTML 必须走 .docx 路线。

2.3 文件头探测:先看清真实格式再分配处理器

真正干过这事的人都会有经验:文件后缀不可信。WPS 用户经常把一个 RTF 文件直接改名为 .doc 发过来,或者把 HTML 粘贴进文档再另存,后缀千奇百怪。用 POI 硬解析会得到一个“The document is really a RTF file”之类的异常,这是 POI 在提醒你用了错误的解析器。

常见做法是先读文件的前几个字节判断真实类型,再做分发:

try (InputStream in = new FileInputStream(file); BufferedInputStream bin = new BufferedInputStream(in)) { byte[] header = new byte[8]; int read = bin.read(header); if (read < 4) { return null; } // PK 开头是 zip 容器(docx、xlsx 都是) if (header[0] == 'P' && header[1] == 'K') { // 按 docx 处理 } // D0 CF 11 E0 是 OLE 复合文档(doc) else if ((header[0] & 0xFF) == 0xD0 && (header[1] & 0xFF) == 0xCF) { // 按 doc 处理 } // 7B 5C 72 74 66 是 {\rtf 文本流 else if (header[0] == '{' && header[1] == '\\') { // 按 RTF 处理,需要转换后再用 POI } }

这里只读 4 到 8 个字节做魔数判断,前缀匹配到 PK 就说明是 OOXML 系列,D0 CF 11 E0 是 OLE2 系列。这样分配处理器之后,后续的异常处理一下子清爽很多。我一般还会把识别失败的样本单独列入一个“不支持格式”列表,记录文件路径和疑似格式,而不是直接丢给用户报错。

3. 段落、图片、表格的 HTML 映射:样式转换与资源内嵌

3.1 段落与字体:中文字体名为什么总在 eastAsia 属性里

XWPFParagraph 是一段文本的容器,里面包含多个 XWPFRun,每个 Run 代表一段相同格式的文本。按 Run 逐个读样式再拼 HTML 是最常用的方式。字体要分两套看:西文字体直接用 run.getFontFamily(),但中文字体藏得比较深,在 XML 里对应的是 rFonts 标签的 eastAsia 属性。

经常有人踩这个坑——用 getFontFamily() 拿到的是西文字体,中文字体永远是样式缺失。得绕到底层 CTTextFont 去读:

private String getEastAsiaFont(XWPFRun run) { if (run.getCTR().getRPr() == null) { return null; } CTTextFont fonts = run.getCTR().getRPr().getRFonts(); if (fonts != null && fonts.getEastAsia() != null) { return fonts.getEastAsia(); } return null; }

这里先判空再取 eastAsia,因为很多 Run 的 RPr 可能没写过字体属性。拼接 HTML 时优先级应该是:中文字体优先用 eastAsia,其次用 getFontFamily() 兜底,都没有就不写 font-family,交给 CSS 默认字体处理。

字号也要注意单位换算问题。getFontSize() 返回的单位是半点(half-point),比如 12 表示 12pt 的一半吗?不是,12 表示 6pt?不对,这里容易记反。POI 里返回的数值是以“点的一半”为单位的,实际 pt 值 = 返回值 / 2。比如宋体五号通常写 10.5pt,POI 返回 21。转 HTML 时我习惯把它换算成 px:px = pt * 96 / 72,也就是 pt 乘以 4/3。

颜色同理,getColor() 返回的是 RGB 十六进制字符串,比如 “FF0000”,有些 Run 没设置颜色会返回 null,输出时要用默认继承值代替。

3.2 图片内嵌:用 Base64 存进 HTML 的取舍

Word 里的图片挂在哪个位置,决定了提取方式。最常见的是内嵌图片,POI 通过 XWPFRun.getEmbeddedPictures() 能直接拿到,转换成 Base64 data URI 写进<img>是最省事的方案:

for (XWPFRun run : paragraph.getRuns()) { List<XWPFPicture> pictures = run.getEmbeddedPictures(); if (pictures.isEmpty()) { continue; } for (XWPFPicture pic : pictures) { XWPFPictureData data = pic.getPictureData(); String mime = data.getMimeType(); String base64 = Base64.getEncoder().encodeToString(data.getData()); String imgTag = String.format( "<img src=\"data:%s;base64,%s\" alt=\"image\" />", mime, base64); output.append(imgTag); } }

mime 类型大多为 image/png 或 image/jpeg,直接用图片数据的 MIME 不带默认值。Base64 内嵌的好处是单文件部署,图片不会丢失,缺点是把 HTML 体积放大约 33%,一张 5MB 的图转完 Base64 有 6.7MB。如果转换结果是要存库并反复传输的,就得权衡一下,超过 500KB 的图我会单独落盘到 static 目录,HTML 里只写相对路径,避免页面首次加载被超大 data URI 拖死。

落在段落文字之间的内嵌图片按顺序拼就行,但如果图片是 floating 类型,Word 里设置了文字环绕,这种图的挂载方式完全不同,getEmbeddedPictures() 拿不到,得在后续排查章里单独讲。

3.3 表格转换:合并单元格与列宽预设的读取

Word 表格转 HTML 表格,最大的差异在结构不齐上。Word 的表格用 tblGrid 声明列数,用 tc 声明单元格,每个 tr 里的 tc 数量可能不一样,存在垂直合并时甚至会在某一行里缺少对应列。直接遍历 XWPFTable、XWPFTableRow 再逐行取 cell 会出现列错位。

我一般先把结构读出来,再补成完整的 HTML 表格:

for (XWPFTable table : doc.getTables()) { StringBuilder tableHtml = new StringBuilder("<table>"); for (XWPFTableRow row : table.getRows()) { tableHtml.append("<tr>"); for (XWPFTableCell cell : row.getTableCells()) { String widthTwips = cell.getWidth(); int widthPx = 0; if (widthTwips != null && !widthTwips.isEmpty()) { widthPx = (int) (Integer.parseInt(widthTwips) / 15.0); } tableHtml.append("<td style=\"width:").append(widthPx).append("px\">"); // 递归处理单元格内嵌段落 for (XWPFParagraph p : cell.getParagraphs()) { tableHtml.append(convertParagraph(p)); } tableHtml.append("</td>"); } tableHtml.append("</tr>"); } tableHtml.append("</table>"); }

column width 返回的是缇(twentieths of a point),转 px 的系数是除以 15,不是除以 20。因为 1pt = 20 twips,1px = 0.75pt,所以 20 twips = 1pt = 0.75px,反过来 1px 是 15 twips。很多第一次算列宽的人会拿 20 当系数,出来的列宽会变成 133%,一眼就能看出不对劲。

合并单元格要额外处理 vmeger 和 gridSpan,POI 在 XWPFTableCell 里有 getCTTc().getTcPr() 能拿到 vMerge 与 hMerge 标志。处理合并的细节不少,我在项目里的做法是遇到合并标记就在输出里补 colspan / rowspan,合并属性缺失的表格先按独立单元格输出,保证整体结构可读。

4. 避坑排查:乱码、图片失踪与 WPS 文件的格式差异

4.1 中文乱码是解码问题还是声明问题

现象:转换出的 HTML 在浏览器打开中文全是问号或菱形符号,但控制台里打印的是正常的。

原因分两种:一种是在读取 .doc 时用了平台的默认字符集,Windows 上是 GBK,Linux 上可能是 UTF-8,同一个文件在不同环境结果不一致;另一种是 HTML 文件保存时没有带 meta charset,浏览器猜编码猜错了。第一种是数据流解码错了,第二种是声明错了。

解决:文件字节流统一按 POI 内部机制读取,不要手动 String 转码,docx 内部的 XML 就是 UTF-8。输出 HTML 时在 head 里第一行就写<meta charset="UTF-8">。同时给 Java 进程固定启动参数-Dfile.encoding=UTF-8,避免 getBytes() 这类隐式转码在不同操作系统上行为不一致。

4.2 图片不出来:inline、floating、页眉页脚三种挂载位置

现象:文档里的图片确实存在,正文也很正常,但转出来的 HTML 里<img>数量明显少,有的段落图片直接消失。

原因:图片不都是挂在 body 段落里的。最常见三种挂载位置——inline 内嵌,floating 浮动(文字环绕),以及挂在 header 或 footer 里。getEmbeddedPictures() 只覆盖内嵌在段落 run 中的图片。页眉的 logo 和浮动图都拿不到,floating 图在 XML 里是通过<mc:AlternateContent>或<w:pict>引用的,POI 的 XWPFRun 对它的支持非常有限。

解决:页眉页脚图要遍历 header 和 footer 的所有段落再提取,浮动图没有干净的 API,我一般退一步,从 document.getPackage() 里的 media 部分直接按关系 ID 拉取:

// 遍历所有页眉页脚段落里的内嵌图片 for (XWPFHeader header : doc.getHeaderList()) { for (XWPFParagraph p : header.getParagraphs()) { for (XWPFRun r : p.getRuns()) { for (XWPFPicture pic : r.getEmbeddedPictures()) { // 提取图片并拼进 HTML } } } }

这个方法能覆盖页眉页脚中 80% 的情况。floating 图要再往底层翻,性价比低,我在实际项目中会和需求方确认“能接受浮动图降级为不导出”再决定深度。

4.3 表格列错位:WPS 保存的 docx 列宽信号不一致

现象:同一个表格,Office 打开的 docx 转换后行列整齐,WPS 另存的 docx 转出的表格少列、错位,某些单元格内容跑到了相邻列。

原因:WPS 在写 tblGrid 的时候有时候会缺少部分 gridCol 定义,或者 gridCol 的数量比实际单元格少。按行遍历 getTableCells() 时,每行录入的 tc 数量不一致,又没有 gridCol 做对齐基准,就会错位。

解决:转换前先读取 tblGrid 的列数,作为每行期望的列数基准。行内 tc 不足就用空 td 补齐,多余的先检查是不是 vMerge 的延续,再决定丢弃还是占位。具体实现时,统计最大 tc 数和 gridCol 数取较大者作为统一列数,能处理大部分 WPS 文件:

int expectedCols = table.getCTTbl().getTblGrid().getGridColArray().length; for (XWPFTableRow row : table.getRows()) { int actualCells = row.getTableCells().size(); if (actualCells < expectedCols) { // 补足缺失的 td } else if (actualCells > expectedCols) { // 检查 vMerge,去掉重复合并行 } }

这一层防御逻辑写成工具方法后,我用 200 份不同来源的 docx 做过抽样校验,错位率从 15% 降到了 2% 以内,剩下的基本是 WPS 里手动画的表格,结构本身就是乱的。

4.4 .doc 文件头是 RTF:WPS 导出文件的伪装

现象:某个 .doc 文件一读就抛异常,POI 提示这个文档实际是 RTF 格式。文件在 WPS 里打开显示正常,后缀也确实 .doc。

原因:WPS 的“另存为 .doc”有时并不是生成 OLE2 复合文档,而是写了一个带 .doc 名字的 RTF 内容。WPS 自己能识别这种伪装文件,但 POI 严格按文件头解析,不会认这个后缀。

解决:按第 2 章里的文件头探测逻辑,识别出 RTF 文件后单独走一路处理。服务端有转换能力就用转换工具把它统一转成 docx 后交给 POI,没有转换能力就返回明确的错误提示,让用户用 WPS 另存为 .docx 再上传。这里要注意别让用户去绕过格式限制,直接提示“当前文件是 RTF 纯文本格式,请另存为 docx 后重试”是最省事的选择。

5. 批量转换与性能:内存上限、并发边界与结果缓存

5.1 POI 的内存模型:为什么 docx 转 HTML 容易 OOM

现象:文档多起来了,转换进程执行到一半挂掉,日志里出现java.lang.OutOfMemoryError: Java heap space,而且往往是转换到某个带大图的文档时发生。

原因:XWPFDocument 不像流式解析器那样可以按需读段落,它在构造时就把整个 ZIP 包解压并加载到内存里。一个 50MB 的 docx,解压后的 XML 和媒体资源可能在内存里占到 300MB 以上,如果转完没有及时释放,还堆在队列里等下一个任务,heap 会被迅速塞满。

解决:给转换进程明确的内存上限,并在启动时开好堆转储,方便事后排查是哪个文件吃掉了内存:

java -Xms512m -Xmx2048m \ -XX:+HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath=/data/logs/doc2html.hprof \ -jar doc-converter.jar

-Xmx 给到多少取决于单文档大小预估,常见做法是压测一个最大样本,按它的内存峰值的 2 到 3 倍设定。同时在代码里强制每个 document 用完即关,关闭后把引用置 null,显式通知 GC 可以回收。转大文件时也别一次性读入输入流再传给 POI,XWPFDocument(File)比XWPFDocument(InputStream)在内存占用上略好一点,因为 OPCPackage 能走文件映射路径。

5.2 并发边界:一个 XWPFDocument 实例不能跨线程

现象:开了多线程批量转,结果偶发出现 null pointer 或者字体丢失,有时候图片也乱。单线程跑得好好的,一并发就出错。

原因:POI 的文档对象设计上不是线程安全的,同一个 XWPFDocument 在多线程下共享解析状态,底层那棵 XML 树的访问不加锁,两个线程同时读段落就会拿到不一致的中间态。

解决:并发粒度应该放在“每个线程独立打开自己的 Document 实例”,而不是共享一个 Document 让线程池轮转。上传的文件先存本地临时目录,线程池里每个 worker 拿自己的文件路径,打开、转换、关闭都在同一个线程完成:

ExecutorService pool = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() / 2 ); for (Path file : FileUtils.listFiles(dir)) { pool.submit(() -> { try (XWPFDocument doc = new XWPFDocument(file.toFile())) { String html = convert(doc); writeResult(html, file); } catch (Exception e) { failedFileList.add(file.toString()); } }); }

线程数别直接设成 CPU 核数,因为 POI 整个转换过程 CPU 和内存都吃,开成核心数的一半比较稳妥。所有转换异常的输入文件统一记到失败清单里,跑完再人工处理,比中断整个批次要实用。

5.3 增量缓存:按文件指纹复用转换结果

现象:同一批文档被反复转换,可能是用户重复上传,也可能是定时任务每轮全量刷一遍,转换时间很长,占满了资源。

原因:转换逻辑没有做结果复用,文档内容没变过,却每次都重新解析一遍 XML 和图片,完全是浪费。

解决:用文件的 SHA-256 做内容指纹,指纹相同的直接返回上次的转换结果。文件路径或修改时间不可靠,路径变了内容没变会缓存失效,修改时间变了内容没变也会失效,只有内容哈希能准确判断“这个文档到底变没变”。Redis 存 HTML 字符串,适用于小文档;大 HTML 写本地文件,以哈希值做文件名:

String hash = DigestUtils.sha256Hex(file); Path cacheFile = Paths.get(cacheDir, hash + ".html"); if (Files.exists(cacheFile)) { return Files.readString(cacheFile, StandardCharsets.UTF_8); } String html = doConvert(file); Files.writeString(cacheFile, html, StandardCharsets.UTF_8);

这套缓存在公文归档这种场景里收益特别明显,成百上千个历史合同被不同系统反复抽取,命中缓存后单文档耗时从秒级直接降到毫秒级。要注意的一点是指纹缓存粒度按整个文件算,文档内改了半行字哈希就变,但这个代价完全可接受——总比全量重转省得多。

6. 进阶用法:把片段包成可渲染的完整页面

前面几章产出的都是 HTML 片段,是一串<p>、<table>、<img>拼接体,它还没有 head、没有 CSS、没有合适的文档结构。前端拿到这种片段直接塞进 div 里能显示,但样式大概率跟原始 Word 差得很远。我的做法是准备一个标准的页面模板,把转换结果填进去,同时带上一套针对 Word 内容预设的 CSS。

public String wrapToFullPage(String bodyHtml) { String template = """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body { font-family: "Microsoft YaHei", "SimSun", sans-serif; line-height: 1.7; } p { margin: 0.5em 0; } table { border-collapse: collapse; width: auto; } td, th { border: 1px solid #aaa; padding: 4px 8px; } img { max-width: 100%; height: auto; } @media print { table, tr { page-break-inside: avoid; } } </style> </head> <body> %s </body> </html> """; return String.format(template, bodyHtml); }

模板里几个关键点:table 强制 border-collapse,不然单元格之间会出现双线;img 加 max-width: 100%,防止大图溢出页面;@media print 规则给打印场景保留体验,长表格不会被拦腰切断。

填充之前我还习惯对 bodyHtml 做一道白名单消毒。Word 文档内容是用户可控的,里面如果藏了带 onerror 属性的 img 或 script 标签,直接插入页面就是 XSS 入口。用 jsoup 的 Cleaner 配合 Safelist 把标签限制在 p、span、table、img 这些文本展示类范围内,属性只保留 src、alt、style 子集,其他一律剥掉。做这道动作后生成的 HTML 既能保持版式,又不会把安全问题带进前端。

前端拿到完整页面后,给图片统一加上 loading="lazy" 是一个便宜又有效的优化,尤其文档超过几十张图时,懒加载能让首屏速度提升明显。图片源是 Base64 data URI 还是独立路径不影响这个属性生效。

从那以后我每次做文档转换,都会强制把“文件头探测、正文拆分、图片与表格提取、片段消毒、模板组装”这一整条链路走一遍,流程所花费的开销比修复线上问题要小得多。希望这篇笔记能帮你把 Word 转 HTML 这条路上常见的坑一次排干净。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 16:37:46

Matlab读取EDF文件:从头部解析到批量转换的完整指南

简介&#xff1a;这份资源面向需要在Matlab环境中处理生物医学信号的科研人员、工程师与学生&#xff0c;聚焦于EDF&#xff08;European Data Format&#xff09;文件的读取与解析。EDF是心电、脑电等生理信号记录的通用格式&#xff0c;Matlab本身并未内置直接读取函数&#…

作者头像 李华
网站建设 2026/10/14 16:36:23

小白怎么挖SRC?从核心认知到主流平台+通用规则,保姆级教程

小白怎么挖SRC&#xff1f;从核心认知到主流平台通用规则&#xff0c;保姆级教程 如果你正打算踏入网络安全圈&#xff0c;或者想通过挖漏洞尝尝技术的甜头&#xff0c;那SRC&#xff08;安全应急响应中心&#xff09;绝对是你最好的起步点。它不仅能让你在实战里练练手&#…

作者头像 李华
网站建设 2026/10/14 16:34:45

小功率锂电池组充电器设计:从拓扑选型到量产避坑的工程实践

1. 从零拆解小功率锂电池组充电器的设计逻辑1.1 为什么小功率锂电池组充电是个“看起来简单、做起来坑多”的活小功率锂电池组充电器&#xff0c;通常指的是输出功率在5W到30W之间、给2串到4串锂离子或锂聚合物电池组充电的电源方案。这类方案大量出现在便携音箱、筋膜枪、扫地…

作者头像 李华
网站建设 2026/10/14 16:33:55

B站视频下载爬虫:从Wbi签名到DASH分片下载全链路解析

简介&#xff1a;这是一份面向Python初学者与爬虫实践者的轻量级B站小视频批量下载工具&#xff0c;解决用户手动逐个保存短视频效率低、缺乏进度反馈的痛点。资源为单文件Python脚本&#xff08;task_4.py&#xff09;&#xff0c;压缩包仅1个ZIP文件、大小2KB&#xff0c;代码…

作者头像 李华
网站建设 2026/10/14 16:33:17

STM32与迪文屏串口通信:协议帧解析与实战例程精讲

简介&#xff1a;面向嵌入式开发者的 STM32 与迪文 DGUS 屏串口通信例程&#xff0c;重点演示基于 HAL 库的 UART 通信与 DGUS 协议交互&#xff0c;覆盖工业控制、智能家居、医疗设备等人机界面开发场景。资源包共 998 个文件&#xff0c;以 647 个 C 源码和 173 个头文件为主…

作者头像 李华