Apache POI 5.5.1 构建并运行示例应用指南

Apache POI 5.5.1 构建并运行示例应用指南(SDK 使用示例):从零创建 Maven 工程、完整 pom.xml、XSSFWorkbook 写入与 FileInputStream 读回示例源码、编译运行命令与真实回显(写出 3379 bytes 的 /tmp/demo.xlsx 并逐格读回,含中文数据全部一致,退出码 0),含依赖树核对与 JVM 堆限制要点。

Apache POIApache POI2026/10/11

Apache POI 5.5.1 构建并运行示例应用指南

目标:从零构建并运行一个基于 Apache POI 5.5.1 的最小 Excel(.xlsx) 写读应用(SDK 使用示例)。给出完整 pom.xml、示例 Java 源码、编译与运行命令及真实回显:XSSFWorkbook 在内存中创建工作簿并写出 /tmp/demo.xlsx(3379 bytes),再用 FileInputStream 读回逐格打印,数据(含中文"中国-测试")全部一致、退出码 0。所有命令与输出均在 Ubuntu 22.04.5 + OpenJDK 17 环境实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS
  • 架构:x86_64
  • Java:OpenJDK 17.0.20.1(headless,仅命令行运行)
  • 构建工具:Apache Maven 3.6.3(Maven home: /usr/share/maven)
  • POI 版本:5.5.1(唯一依赖 poi-ooxml,第三方依赖由 Maven 自动传递引入)
  • 示例工程目录:/opt/data/poi-demo/
  • 输出文件:/tmp/demo.xlsx
  • 运行账号:root

💡 说明:Apache POI 是 Java 类库(SDK),以 Maven 依赖形态使用,没有独立守护进程;"运行示例"即在 JVM 中执行引用了 POI jar 的 Java 主类。

二、前置条件

  • 已安装 OpenJDK 17 与 Maven(安装过程见《Ubuntu 22.04 安装 Apache POI 5.5 指南》),并确认版本满足要求:
java -version

真实回显:

openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
mvn -version

真实回显:

Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 17.0.20.1, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: en_US, platform encoding: ANSI_X3.4-1968
  • 首次编译需可访问 Maven Central(repo1.maven.org)下载 poi-ooxml:5.5.1 及其传递依赖。

三、工程结构

标准 Maven 布局,一个 pom 与一个主类,外加构建期生成的 classpath 文件:

poi-demo/
├── pom.xml
├── src/main/java/PoiXlsxDemo.java
└── cp.txt(由 dependency:build-classpath 生成)

创建工程目录:

mkdir -p /opt/data/poi-demo/src/main/java

四、完整 pom.xml

编写 /opt/data/poi-demo/pom.xml,仅引入唯一依赖 poi-ooxml:5.5.1(其余第三方依赖自动传递引入):

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>poi-demo</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>
  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>5.5.1</version>
    </dependency>
  </dependencies>
</project>

4.1 依赖树核对(可选)

构建前可用 mvn dependency:tree 核对传递依赖是否完整:

cd /opt/data/poi-demo && mvn dependency:tree -Dscope=compile

真实回显:

com.example:poi-demo:jar:1.0
\- org.apache.poi:poi-ooxml:jar:5.5.1:compile
   +- org.apache.poi:poi:jar:5.5.1:compile
   |  +- commons-codec:commons-codec:jar:1.20.0:compile
   |  +- org.apache.commons:commons-math3:jar:3.6.1:compile
   |  \- com.zaxxer:SparseBitSet:jar:1.3:compile
   +- org.apache.poi:poi-ooxml-lite:jar:5.5.1:compile
   +- org.apache.xmlbeans:xmlbeans:jar:5.3.0:compile
   +- org.apache.commons:commons-compress:jar:1.28.0:compile
   |  \- org.apache.commons:commons-lang3:jar:3.18.0:compile
   +- commons-io:commons-io:jar:2.21.0:compile
   +- com.github.virtuald:curvesapi:jar:1.08:compile
   +- org.apache.logging.log4j:log4j-api:jar:2.24.3:compile
   \- org.apache.commons:commons-collections4:jar:4.5.0:compile

💡 说明:POI 5.x 不再依赖旧的 poi-ooxml-schemas 构件,改由 poi-ooxml-lite 承载精简 schema 类(poi-ooxml-schemas 在 4.x 起已废弃)。

五、示例源码

创建 /opt/data/poi-demo/src/main/java/PoiXlsxDemo.java,程序完成三步:XSSFWorkbook 在内存中创建工作簿写入 3 行数据 → 写出 /tmp/demo.xlsx → 用 FileInputStream 读回逐格打印:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/** 演示: XSSFWorkbook 在内存中创建 .xlsx 写入, 再用 FileInputStream 读回打印 */
public class PoiXlsxDemo {
    public static void main(String[] args) throws Exception {
        String path = "/tmp/demo.xlsx";

        // ===== 写 =====
        try (Workbook wb = new XSSFWorkbook()) {
            Sheet sheet = wb.createSheet("Demo");
            // 表头
            Row header = sheet.createRow(0);
            header.createCell(0).setCellValue("Name");
            header.createCell(1).setCellValue("Value");
            // 数据行
            Row row = sheet.createRow(1);
            row.createCell(0).setCellValue("Hello POI");
            row.createCell(1).setCellValue(42);
            Row row2 = sheet.createRow(2);
            row2.createCell(0).setCellValue("中国-测试");
            row2.createCell(1).setCellValue(3.14);

            try (FileOutputStream fos = new FileOutputStream(path)) {
                wb.write(fos);
            }
        }
        System.out.println("[WRITE] 已写出文件: " + path +
            ", 大小=" + new File(path).length() + " bytes" +
            " (=" + String.format("%.1f", new File(path).length() / 1024.0) + " KB)");

        // ===== 读 =====
        try (FileInputStream fis = new FileInputStream(path);
             Workbook wb = new XSSFWorkbook(fis)) {
            Sheet sheet = wb.getSheetAt(0);
            System.out.println("[READ] Sheet count=" + wb.getNumberOfSheets() +
                ", first sheet name=\"" + sheet.getSheetName() + "\"");
            for (Row r : sheet) {
                for (Cell c : r) {
                    DataFormatter fmt = new DataFormatter();
                    String val = fmt.formatCellValue(c);
                    System.out.printf("[READ] R%dC%d = %s%n",
                        r.getRowNum(), c.getColumnIndex(), val);
                }
            }
        }
        System.out.println("[DONE] 写读演示完成");
    }
}

💡 读取单元格用 DataFormatter.formatCellValue(Cell):按单元格显示格式输出字符串,数字 42、3.14 均按原样打印,避免自行区分 CellType。

六、编译与运行

6.1 编译打包

cd /opt/data/poi-demo && mvn -q package

-q 为静默模式,无输出且退出码 0 即构建成功;产物在 target/classes/。

6.2 生成运行 classpath

cd /opt/data/poi-demo && mvn -q dependency:build-classpath -Dmdep.outputFile=/opt/data/poi-demo/cp.txt

该命令把全部依赖 jar 的绝对路径写入 cp.txt,供 java -cp 使用。

6.3 运行示例

说明:系统 locale 非 UTF-8(如本环境的 ANSI_X3.4-1968)时,需加 -Dfile.encoding=UTF-8 才能正常输出中文,否则 System.out 中文显示为 ?(乱码);写入文件内容本身不受影响。

cd /opt/data/poi-demo && java -Dfile.encoding=UTF-8 -cp "target/classes:$(cat cp.txt)" PoiXlsxDemo

真实回显(退出码 0):

2026-10-11T11:27:04.652091124Z main ERROR Log4j API could not find a logging provider.
[WRITE] 已写出文件: /tmp/demo.xlsx, 大小=3379 bytes (=3.3 KB)
[READ] Sheet count=1, first sheet name="Demo"
[READ] R0C0 = Name
[READ] R0C1 = Value
[READ] R1C0 = Hello POI
[READ] R1C1 = 42
[READ] R2C0 = 中国-测试
[READ] R2C1 = 3.14
[DONE] 写读演示完成

6.4 JVM 堆内存限制

POI 处理大文件时内存占用较高,建议把构建期 Maven 进程与运行期示例进程的堆限制在 256–512MB。构建期通过 MAVEN_OPTS 注入:

export MAVEN_OPTS="-Xms256m -Xmx512m -Xmn128m"

运行期在 6.3 节命令基础上追加堆参数:

⚠️ 以下命令为 6.3 节命令的堆限制变体(仅追加 JVM 参数 -Xms256m -Xmx512m,不改变程序输出;本批实测回显以 6.3 节为准)。

cd /opt/data/poi-demo && java -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -cp "target/classes:$(cat cp.txt)" PoiXlsxDemo

验证 Maven 进程实际生效的堆参数(另开终端):

jps -v

jps -v 会列出所有 Java 进程及其 JVM 参数,确认 -Xms256m -Xmx512m 出现在对应进程参数中即生效。

七、输出验证:文件大小与 xlsx 内部结构

查看输出文件:

ls -l /tmp/demo.xlsx

真实回显:

-rw-r--r-- 1 root root 3379 Oct 11 11:27 /tmp/demo.xlsx   # 3379 bytes ≈ 3.3 KB

xlsx 本质是 ZIP 包,用 unzip -l 查看内部结构:

unzip -l /tmp/demo.xlsx

真实回显:

Archive:  /tmp/demo.xlsx
  Length      Date    Time    Name
---------  ---------- -----   ----
     1053  2026-10-11 11:27   [Content_Types].xml
      586  2026-10-11 11:27   _rels/.rels
      183  2026-10-11 11:27   docProps/app.xml
      433  2026-10-11 11:27   docProps/core.xml
      237  2026-10-11 11:27   xl/sharedStrings.xml
      674  2026-10-11 11:27   xl/styles.xml
      347  2026-10-11 11:27   xl/workbook.xml
      564  2026-10-11 11:27   xl/_rels/workbook.xml.rels
      639  2026-10-11 11:27   xl/worksheets/sheet1.xml
---------                     -------
     4716                     9 files

结果解读:

  • [Content_Types].xml 为包清单,xl/ 下是工作簿主体(workbook.xml、sharedStrings.xml、styles.xml、worksheets/sheet1.xml),docProps/ 为文档元数据。
  • 程序退出码 0、读回数据与写入一致(含中文"中国-测试")、输出文件结构与 OOXML 规范相符,即视为示例构建运行成功。

八、注意事项

⚠️ 注意:

  1. JDK 要求:POI 5.5.x 需 JDK 8+(官方 RELEASE-NOTES 载明 "build all POI components with JDK 1.8 or higher");本示例用 JDK 17 + Maven 3.6.3 编译运行正常。
  2. 依赖链:核心第三方依赖为 commons-codec / commons-math3 / SparseBitSet / xmlbeans / commons-compress(+commons-lang3) / commons-io / curvesapi / log4j-api / commons-collections4,Maven 自动传递引入,无需手工添加。
  3. 日志警告:首行 Log4j API could not find a logging provider. 是 classpath 中仅有 log4j-api(无实现)时 POI 的常规警告,不影响功能;业务工程中引入任一 log4j-core / slf4j 实现即可消除。
  4. 中文编码:终端 locale 非 UTF-8 时,Java 程序需加 -Dfile.encoding=UTF-8(JDK 17+ 亦可设 JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8"),否则 System.out 中文显示乱码;写入文件内容本身不受影响。
  5. 读文件方式:小文件可用 FileInputStream + XSSFWorkbook(本示例方式);大文件推荐 XSSFWorkbook(OPCPackage) / SAX 事件解析,避免整本载入内存。
  6. 版本探测:dlcdn 只保留最近发布(RELEASE-NOTES 载明版本号),完整版本列表查 Maven Central 目录。

九、常见问题

Q1:编译报"程序包 org.apache.poi 不存在"? poi-ooxml 依赖未正确下载或版本拼写错误。检查 ~/.m2/repository/org/apache/poi/ 下是否有 poi-5.5.1.jar、poi-ooxml-5.5.1.jar、poi-ooxml-lite-5.5.1.jar,确认 pom.xml 中 <version>5.5.1</version> 无误后重新构建:

cd /opt/data/poi-demo && mvn -q clean package

Q2:运行时中文输出为问号乱码? 系统 locale 非 UTF-8 所致。加 -Dfile.encoding=UTF-8 或设 JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8" 后重跑即可(见 6.3 与 6.4 节),写入文件内容本身不受影响。

Q3:首行出现 Log4j 警告? classpath 中只有 log4j-api 没有日志实现。该警告不影响功能;如需消除,在 pom.xml 中额外引入任一日志实现(如 log4j-core 或 slf4j)。

Q4:java -cp 报 ClassNotFoundException: PoiXlsxDemo? 未先执行 6.1 编译或 classpath 拼接有误。确认 target/classes/PoiXlsxDemo.class 存在,且 -cp "target/classes:$(cat cp.txt)" 中 target/classes 在前(Linux 分隔符为冒号)。

十、参考链接

  • Apache POI 官网:https://poi.apache.org/
  • Apache POI 官方发布说明:https://dlcdn.apache.org/poi/release/RELEASE-NOTES.txt
  • Maven Central poi-ooxml 版本目录:https://repo1.maven.org/maven2/org/apache/poi/poi-ooxml/