Excel文件解析 - 什么是SAX和DOM

Excel文件本质是XML文件,对应两种解析方式

  • SAX 流式读取,对应 XSSFReader
  • DOM 树读取,对应 Workbook

很好的问题!让我用通俗易懂的方式解释 SAX 和 DOM 这两种 XML 解析模式。

核心概念

XML 解析器读取 XML 文件时有两种基本策略:

  • SAX:边读边处理(流式)
  • DOM:全部读入后再处理(树状)

SAX (Simple API for XML)

工作原理

复制代码
XML 文件:  →   解析器  →  事件触发  →  你的代码处理
<root>          ↓           ↓
  <a>1</a>   开始读取   "遇到开始标签 <a>"
  <b>2</b>   继续读取   "遇到开始标签 <b>"
</root>       ↓           ↓
           继续读取   "遇到内容 2"
                      "遇到结束标签 </b>"
                      "遇到结束标签 </a>"
                      ...

代码示例

java 复制代码
// SAX 解析器会回调这些方法
public class MyHandler extends DefaultHandler {
    @Override
    public void startElement(String uri, String name, String qName, Attributes atts) {
        System.out.println("开始标签: " + qName);
    }
    
    @Override
    public void characters(char ch[], int start, int length) {
        System.out.println("内容: " + new String(ch, start, length));
    }
    
    @Override
    public void endElement(String uri, String name, String qName) {
        System.out.println("结束标签: " + qName);
    }
}

生活中的类比:流水线工人

  • 你站在流水线旁
  • 产品(数据)一个接一个经过
  • 你看到一个就处理一个
  • 不需要记住之前的产品
  • 优点:省空间,速度快
  • 缺点:不能回头看前面的产品

SAX 的特点

优点 缺点
✅ 内存占用极低 ❌ 只能顺序读取
✅ 处理速度快 ❌ 不能随机访问
✅ 适合大文件 ❌ 代码稍复杂
✅ 可以随时停止 ❌ 需要自己维护状态

DOM (Document Object Model)

工作原理

复制代码
XML 文件:  →   解析器  →  内存中的树  →  你的代码操作
<root>          ↓           ↓
  <a>1</a>   全部读取    root
  <b>2</b>   构建树      ├── a: "1"
</root>                  └── b: "2"
                         整棵树都在内存中!

代码示例

java 复制代码
// DOM 解析后,整个文档树都在内存中
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("data.xml"));

// 可以随意访问任何节点
NodeList nodes = doc.getElementsByTagName("a");
for (int i = 0; i < nodes.getLength(); i++) {
    System.out.println(nodes.item(i).getTextContent());
}

// 可以修改节点
nodes.item(0).setTextContent("新值");

// 可以添加新节点
Element newElement = doc.createElement("c");
newElement.setTextContent("3");
doc.getDocumentElement().appendChild(newElement);

生活中的类比:图书馆管理员

  • 把所有书(数据)都搬到阅览室
  • 可以随时去翻任何一本书
  • 可以在书上做笔记、修改
  • 但需要很大的阅览室(内存)
  • 优点:灵活方便
  • 缺点:占空间,搬书耗时间

DOM 的特点

优点 缺点
✅ 可以随机访问任何节点 ❌ 内存占用高
✅ 可以修改文档 ❌ 加载整个文件慢
✅ 可以遍历多次 ❌ 不适合大文件
✅ 代码简单直观 ❌ 需要等待全部加载

直观对比

读取一个 10MB 的 XML 文件

SAX 方式
复制代码
内存占用:约 20MB
处理时间:1 秒
工作方式:像看电视,边播边看
DOM 方式
复制代码
内存占用:约 200MB+
处理时间:3 秒
工作方式:像下载电影,全下载完再看

具体示例对比

假设有这个 XML 文件:

xml 复制代码
<students>
    <student id="1">
        <name>张三</name>
        <age>20</age>
    </student>
    <student id="2">
        <name>李四</name>
        <age>21</age>
    </student>
    <student id="3">
        <name>王五</name>
        <age>22</age>
    </student>
</students>

SAX 处理流程(事件驱动)

复制代码
1. 开始标签 <students>    → 触发 startElement()
2. 开始标签 <student>     → 触发 startElement()
3. 开始标签 <name>        → 触发 startElement()
4. 内容 "张三"            → 触发 characters()
5. 结束标签 </name>       → 触发 endElement()
6. 开始标签 <age>         → 触发 startElement()
7. 内容 "20"              → 触发 characters()
8. 结束标签 </age>        → 触发 endElement()
9. 结束标签 </student>    → 触发 endElement()
...(继续处理后面的学生)

DOM 处理流程(树状结构)

复制代码
加载完成后,内存中是这样的树:

Document
 └── students
      ├── student (id="1")
      │    ├── name: "张三"
      │    └── age: "20"
      ├── student (id="2")
      │    ├── name: "李四"
      │    └── age: "21"
      └── student (id="3")
           ├── name: "王五"
           └── age: "22"

然后你可以:
- 直接访问第3个学生:doc.getElementsByTagName("student").item(2)
- 修改年龄:student.getElementsByTagName("age").item(0).setTextContent("23")
- 删除某个学生
- 添加新学生

什么时候用哪种?

用 SAX 的场景 ✅

  • 📄 大文件(> 10MB)
  • 🚀 只需要读取一次(不需要回看)
  • 💾 内存受限(嵌入式设备、高并发场景)
  • 📊 数据导入(Excel、CSV 等批量处理)
  • 🔍 提取特定信息(比如只找某个标签的内容)

用 DOM 的场景 ✅

  • 📝 需要修改文档(增删改)
  • 🔀 需要随机访问(跳到任意位置)
  • 🔄 需要多次遍历
  • 📦 小文件(< 1MB)
  • 🛠️ 复杂查询(XPath、XSLT)
  • 🎨 需要结构化操作(维护文档关系)

回到你的 Excel 解析问题

java 复制代码
// SAX 方式(你看到的第一个代码)
XMLReader parser = XMLReaderFactory.createXMLReader(...);
parser.parse(sheetSource);
// 优点:处理 100MB 的 Excel 只需 50MB 内存

// DOM 方式(你看到的第二个代码)
Workbook workbook = WorkbookFactory.create(inputStream);
// 缺点:100MB 的 Excel 可能需要 2GB+ 内存

结论 :Excel 文件本质上是 XML(.xlsx 是 ZIP+XML),批量导入场景下,SAX 是更优的选择!

希望这个解释能帮你理解 SAX 和 DOM 的区别!

相关推荐
二哈赛车手21 分钟前
新人笔记---hermes定时功能设计,具体讲解以及可优化点
java·人工智能·笔记·spring·ai·typescript
ZWZhangYu25 分钟前
从 Dify 实践理解大模型上下文缓存
java·后端·spring
小羊没烦恼!1 小时前
关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁
java·服务器·网络·学习·负载均衡
Fuyo_11192 小时前
C++ AVL树保姆级详解:从平衡因子到四大旋转机制
java·c++·算法
Sarvartha2 小时前
Date、LocalDate、LocalTime、LocalDateTime、DateTimeFormatter类
java
阿俊-全栈开发3 小时前
LikeShop 多商户 Java 版商城微服务模块拆分与部署架构演进实践
java·微服务·架构·likeshop开源商城·多商户源码
Wang's Blog3 小时前
Java 项目实战:交友项目 - 联系人列表
java·开发语言·交友
我命由我123453 小时前
访客系统形式(有用户概念、无用户概念)
java·开发语言·前端·javascript·python·产品运营·产品经理
香蕉大香蕉(06敬畏市场)4 小时前
MySQL 单点详解(01)
java·数据库·mysql·面试·博客·实习
LaughingZhu4 小时前
Product Hunt 热榜 2026-10-30:Empacer、Scape、Floot in ChatGPT
java·前端·数据库·人工智能·chatgpt·notion