介绍java中常用于处理 Excel 文件的Apache POI

介绍java中常用于处理 Excel 文件的Apache POI

一、介绍

Apache POI(Poor Obfuscation Implementation )是 Apache 基金会的开源 Java 库,用于处理 Microsoft Office 格式文件(如 Excel、Word、PowerPoint)。其中,处理 Excel 2007 及以上版本的.xlsx文件需使用XSSF(XML Spreadsheet Format)组件。

二、组件

  • XSSFWorkbook :表示整个.xlsx工作簿(Workbook)。
  • XSSFSheet:表示工作簿中的工作表(Sheet)。
  • XSSFRow:表示工作表中的行(Row)。
  • XSSFCell:表示行中的单元格(Cell)。
  • XSSFCellStyle:单元格样式(字体、颜色、对齐方式等)。
  • XSSFFont:字体样式。

在 Apache POI 处理 Excel 文件的层级模型中,Workbook(工作簿)→ Sheet(工作表)→ Row(行)→ Cell(单元格) 是对 Excel 文件结构的抽象映射,对应 Excel 文件的实际组成部分:

1. Workbook(工作簿)
  • 对应 Excel 文件本身 :一个.xlsx文件就是一个 Workbook(工作簿)。
  • 作用:作为整个 Excel 文件的顶层容器,包含所有工作表(Sheet)、样式、字体等全局资源。
  • POI 实现类:
    • XSSFWorkbook:对应.xlsx格式(Excel 2007+)。
    • SXSSFWorkbook:用于处理大数据量的.xlsx文件(流式处理,低内存占用)。
    • HSSFWorkbook:对应.xls格式(Excel 97-2003,已过时)。

​ 如图:

2. Sheet(工作表)
  • 对应 Excel 中的 "Sheet 标签页":一个工作簿中可以包含多个工作表(如 "Sheet1""Sheet2")。
  • 作用:作为行(Row)和单元格(Cell)的容器,负责组织表格数据结构。
  • POI 实现类:
    • XSSFSheet.xlsx文件的工作表。
    • SXSSFSheet:流式处理的工作表。

​ 如图(一个Workbook下的两个不同的Sheet):

3. Row(行)
  • 对应 Excel 表格中的一行 :每个工作表由若干行组成,行索引从0开始(第一行是 Row 0)。
  • 作用:作为单元格(Cell)的直接容器,每行包含多个单元格。
  • POI 实现类:
    • XSSFRow.xlsx文件的行。
    • 注意:行对象可能为null(表示该行无数据)。

​ 如图:

4. Cell(单元格)
  • 对应 Excel 表格中的单元格 :每行由若干单元格组成,列索引从0开始(第一列是 Cell 0)。
  • 作用:存储具体的数据(文本、数字、公式、布尔值等),并可设置样式。
  • POI 实现类:
    • XSSFCell.xlsx文件的单元格。
    • 注意:单元格对象可能为null(表示该位置无数据)。

如图:

层级关系示例

一个 Excel 文件的结构可理解为:

students.xlsx(Workbook) → "学生信息表"(Sheet) → 第 0 行(Row 0:表头行) → 第 0 列单元格(Cell 0:"学号")、第 1 列单元格(Cell 1:"姓名")......

三、实现

1、引入依赖

最新版本可参考Apache POI 官网

xml 复制代码
<!-- 核心POI库 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.5</version>
</dependency>
<!-- 处理XSSF (.xlsx) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.5</version>
</dependency>
<!-- 可选:处理公式 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>
<!-- 可选:XML解析依赖 -->
<dependency>
    <groupId>org.apache.xmlbeans</groupId>
    <artifactId>xmlbeans</artifactId>
    <version>5.1.1</version>
</dependency>
Apache POI 版本与 JDK 对应表:
Apache POI 版本 最低 JDK 版本 推荐 JDK 版本 备注
3.x 系列(如 3.17、3.19) JDK 6 JDK 6/7/8 兼容老项目,已停止维护
4.x 系列(如 4.1.2、4.2.2) JDK 8 JDK 8/11 主流稳定版本,兼容大部分场景
5.x 系列(如 5.2.0、5.2.5) JDK 11 JDK 11/17 最新特性支持,推荐 JDK 11+
5.2.3+ JDK 11 JDK 11/17/21 适配更高版本 JDK,支持模块化
2、基础操作:创建.xlsx 文件
简单创建工作簿、工作表、行和单元格
java 复制代码
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFCell;

import java.io.FileOutputStream;
import java.io.IOException;

public class CreateXlsxExample {
    public static void main(String[] args) {
        // 1. 创建工作簿
        XSSFWorkbook workbook = new XSSFWorkbook();
        
        // 2. 创建工作表(指定名称)
        XSSFSheet sheet = workbook.createSheet("学生信息表");
        
        // 3. 创建行(行索引从0开始)
        XSSFRow headerRow = sheet.createRow(0); // 表头行
        
        // 4. 创建单元格并设置值(列索引从0开始)
        XSSFCell cell0 = headerRow.createCell(0);
        cell0.setCellValue("学号");
        
        XSSFCell cell1 = headerRow.createCell(1);
        cell1.setCellValue("姓名");
        
        XSSFCell cell2 = headerRow.createCell(2);
        cell2.setCellValue("年龄");
        
        // 5. 创建数据行
        XSSFRow dataRow = sheet.createRow(1);
        dataRow.createCell(0).setCellValue(1001);
        dataRow.createCell(1).setCellValue("张三");
        dataRow.createCell(2).setCellValue(20);
        
        // 6. 自动调整列宽
        sheet.autoSizeColumn(0);
        sheet.autoSizeColumn(1);
        sheet.autoSizeColumn(2);
        
        // 7. 写入文件
        try (FileOutputStream outputStream = new FileOutputStream("students.xlsx")) {
            workbook.write(outputStream);
            System.out.println("xlsx文件创建成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭工作簿
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
3、读取.xlsx 文件
读取单元格值(区分数据类型)
java 复制代码
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.ss.usermodel.CellType;

import java.io.FileInputStream;
import java.io.IOException;

public class ReadXlsxExample {
    public static void main(String[] args) {
        try (FileInputStream inputStream = new FileInputStream("students.xlsx");
             XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
            
            // 1. 获取工作表(通过名称或索引)
            XSSFSheet sheet = workbook.getSheet("学生信息表");
            // XSSFSheet sheet = workbook.getSheetAt(0); // 通过索引(0开始)
            
            // 2. 遍历行
            for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
                XSSFRow row = sheet.getRow(rowNum);
                if (row == null) continue; // 跳过空行
                
                // 3. 遍历单元格
                for (int cellNum = 0; cellNum < row.getLastCellNum(); cellNum++) {
                    XSSFCell cell = row.getCell(cellNum);
                    if (cell == null) continue; // 跳空单元格
                    
                    // 4. 根据单元格类型读取值
                    String cellValue = switch (cell.getCellType()) {
                        case STRING -> cell.getStringCellValue();
                        case NUMERIC -> String.valueOf(cell.getNumericCellValue());
                        case BOOLEAN -> String.valueOf(cell.getBooleanCellValue());
                        case FORMULA -> cell.getCellFormula(); // 公式
                        default -> "";
                    };
                    System.out.print(cellValue + "\t");
                }
                System.out.println();
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
4、进阶操作:设置单元格样式
设置字体、对齐方式、背景色
java 复制代码
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;

import java.io.FileOutputStream;
import java.io.IOException;

public class StyleXlsxExample {
    public static void main(String[] args) {
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("样式示例");
        
        // 1. 创建字体样式
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 12);
        font.setBold(true); // 加粗
        font.setColor(IndexedColors.RED.getIndex()); // 红色
        
        // 2. 创建单元格样式
        XSSFCellStyle style = workbook.createCellStyle();
        style.setFont(font);
        style.setAlignment(HorizontalAlignment.CENTER); // 水平居中
        style.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
        style.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex()); // 背景色
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        
        // 3. 应用样式到单元格
        XSSFRow row = sheet.createRow(0);
        XSSFCell cell = row.createCell(0);
        cell.setCellValue("带样式的单元格");
        cell.setCellStyle(style);
        
        // 写入文件
        try (FileOutputStream outputStream = new FileOutputStream("styled.xlsx")) {
            workbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
5、其他常用功能
合并单元格
java 复制代码
// 合并第一行第0列到第2列的单元格
CellRangeAddress mergedRegion = new CellRangeAddress(0, 0, 0, 2);
sheet.addMergedRegion(mergedRegion);
设置单元格数据类型
java 复制代码
XSSFCell cell = row.createCell(0);
cell.setCellType(CellType.NUMERIC); // 数值型
cell.setCellValue(99.9);

XSSFCell cell2 = row.createCell(1);
cell2.setCellType(CellType.BOOLEAN); // 布尔型
cell2.setCellValue(true);
写入公式
java 复制代码
XSSFCell formulaCell = row.createCell(3);
formulaCell.setCellFormula("SUM(A2:C2)"); // 求和公式

四、注意

  1. 内存占用 :XSSF 处理大文件时(如 10 万行以上)会占用大量内存,建议使用SXSSF(Streaming XSSF)进行大数据量处理(SXSSF 通过临时文件缓存数据,降低内存占用)。
  2. 单元格索引 :行和列的索引均从0开始。
  3. 空行 / 空单元格处理getRow(rowNum)getCell(cellNum)可能返回null,需判空避免空指针。
  4. 文件关闭 :必须通过workbook.close()关闭工作簿,释放资源;使用 try-with-resources 语法自动关闭流。
SXSSF(大数据量处理)示例
java 复制代码
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;

public class BigDataXlsxExample {
    public static void main(String[] args) {
        // SXSSFWorkbook(100):保留100行在内存,超过则写入临时文件
        SXSSFWorkbook workbook = new SXSSFWorkbook(100);
        SXSSFSheet sheet = workbook.createSheet("大数据表");
        
        // 写入10万行数据
        for (int i = 0; i < 100000; i++) {
            XSSFRow row = sheet.createRow(i);
            row.createCell(0).setCellValue("数据" + i);
            row.createCell(1).setCellValue(i);
        }
        
        try (FileOutputStream outputStream = new FileOutputStream("bigdata.xlsx")) {
            workbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            workbook.dispose(); // 清除临时文件
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

五、总结

Apache POI 处理.xlsx文件(XSSF/SXSSF)的常用方法按照工作簿、工作表、行、单元格、样式、高级操作分类总结:

1、工作簿(Workbook)相关方法
方法 说明
new XSSFWorkbook() 创建新的.xlsx工作簿
new XSSFWorkbook(InputStream) 从输入流读取已存在的工作簿
new SXSSFWorkbook(int rowAccessWindowSize) 创建支持大数据量的 SXSSF 工作簿(指定内存缓存行数)
workbook.createSheet(String sheetName) 创建指定名称的工作表
workbook.getSheet(String sheetName) 通过名称获取工作表
workbook.getSheetAt(int index) 通过索引(从 0 开始)获取工作表
workbook.removeSheetAt(int index) 删除指定索引的工作表
workbook.write(OutputStream) 将工作簿写入输出流(文件 / 网络)
workbook.close() 关闭工作簿,释放资源
sxssfWorkbook.dispose() SXSSF 专用:清除临时文件,释放磁盘空间
2、工作表(Sheet)相关
方法 说明
sheet.createRow(int rowNum) 创建指定行号的行(行号从 0 开始)
sheet.getRow(int rowNum) 获取指定行号的行(不存在返回null
sheet.getLastRowNum() 获取最后一行的行号(无数据行返回 - 1)
sheet.autoSizeColumn(int columnIndex) 自动调整指定列的宽度
sheet.setColumnWidth(int columnIndex, int width) 设置列宽(单位:1/256 个字符宽度)
sheet.addMergedRegion(CellRangeAddress) 合并单元格(如new CellRangeAddress(0,0,0,2)表示合并第 0 行 0-2 列)
sheet.removeMergedRegion(int index) 移除指定索引的合并单元格区域
sheet.setDefaultRowHeight(short height) 设置默认行高(单位:1/20 个点)
3、行(Row)相关
方法 说明
row.createCell(int columnIndex) 创建指定列号的单元格(列号从 0 开始)
row.getCell(int columnIndex) 获取指定列号的单元格(不存在返回null
row.getLastCellNum() 获取最后一列的列号(无单元格返回 - 1)
row.setRowNum(int rowNum) 设置行号
row.setHeight(short height) 设置行高
row.removeCell(Cell cell) 移除指定单元格
4、单元格(Cell)相关
方法 说明
cell.setCellValue(Object value) 设置单元格值(支持 String/Number/Boolean/Date 等)
cell.getCellType() 获取单元格类型(如CellType.STRING/CellType.NUMERIC
cell.getStringCellValue() 获取字符串类型单元格的值
cell.getNumericCellValue() 获取数值类型单元格的值
cell.getBooleanCellValue() 获取布尔类型单元格的值
cell.setCellFormula(String formula) 设置单元格公式(如"SUM(A1:B1)"
cell.getCellFormula() 获取单元格公式
cell.setCellStyle(CellStyle style) 应用样式到单元格
cell.setCellType(CellType type) 设置单元格数据类型(如CellType.FORMULA

5、样式与格式相关

单元格样式(CellStyle)
方法 说明
workbook.createCellStyle() 创建新的单元格样式
style.setFont(Font font) 设置字体样式
style.setAlignment(HorizontalAlignment align) 设置水平对齐(如HorizontalAlignment.CENTER
style.setVerticalAlignment(VerticalAlignment align) 设置垂直对齐(如VerticalAlignment.CENTER
style.setFillForegroundColor(IndexedColors color) 设置背景色(需配合填充模式)
style.setFillPattern(FillPatternType pattern) 设置填充模式(如FillPatternType.SOLID_FOREGROUND
style.setBorderTop(BorderStyle style) 设置上边框样式(如BorderStyle.THIN
style.setTopBorderColor(IndexedColors color) 设置上边框颜色
字体(Font)
方法 说明
workbook.createFont() 创建新字体
font.setFontName(String name) 设置字体名称(如 "宋体""Arial")
font.setFontHeightInPoints(short size) 设置字体大小(单位:磅)
font.setBold(boolean bold) 设置加粗
font.setColor(IndexedColors color) 设置字体颜色
font.setItalic(boolean italic) 设置斜体

6、高级操作

方法 / 工具类 说明
CellRangeAddress.valueOf(String range) 通过字符串(如 "A1:C3")创建单元格合并区域
DataFormatter.formatCellValue(Cell cell) 格式化单元格值(按 Excel 显示格式输出,如日期、百分比)
FormulaEvaluator.evaluate(Cell cell) 计算公式单元格的结果(返回CellValue
sheet.setRowSumsBelow(boolean sumsBelow) 设置汇总行位置(用于公式计算)

核心操作逻辑

  1. 通过 Workbook 获取 Sheet;
  2. 通过 Sheet 获取 Row;
  3. 通过 Row 获取 Cell;
  4. 对 Cell 进行读写或样式设置。
相关推荐
八饱粥40 分钟前
excel数据导入mysql数据库
数据库·mysql·excel
路边草随风40 分钟前
java 实现 flink 读 kafka 写 iceberg
java·flink·kafka
路边草随风42 分钟前
java 实现 flink cdc 读 mysql binlog 按表写入kafka不同topic
java·大数据·mysql·flink
低客的黑调42 分钟前
Spring MVC 全面详解:原理、组件、实战与高级特性
java·spring·mvc
STARFALL00142 分钟前
spring mvc 自定义Converter 设置
java·spring·mvc
java_logo43 分钟前
Jenkins Docker 容器化部署指南
java·运维·servlet·docker·容器·jdk·jenkins
꧁坚持很酷꧂44 分钟前
Ubuntu系统下通过第三方库QtXlsx输出Excel(图文详解)
ubuntu·excel
♡喜欢做梦1 小时前
MyBatis操作数据库(进阶):动态SQL
java·数据库·sql·java-ee·mybatis
祝威廉1 小时前
InfiniSynapse: 把PDF里的表格和Excel/业务数据联合分析
pdf·excel