杰瑞科技汇

Java POI写入Excel如何操作?

POI 简介

Apache POI 是一个开源的 Java 库,用于操作 Microsoft Office 格式的文件,如 Word、Excel、PowerPoint 等,对于 Excel,POI 提供了两种主要的 API:

Java POI写入Excel如何操作?-图1
(图片来源网络,侵删)
  • HSSF (Horrible Spreadsheet Format): 用于操作 Excel 97-2003 格式的文件(.xls),这种格式最多支持 65536 行和 256 列。
  • XSSF (XML Spreadsheet Format): 用于操作 Excel 2007 及以上版本的格式(.xlsx),这种格式基于 OpenXML 标准,支持更大的行数和列数(理论上是 1048576 行 x 16384 列)。

强烈推荐使用 XSSF,因为 .xlsx 是目前的主流格式,性能和兼容性都更好。


添加 Maven 依赖

你需要在你的 pom.xml 文件中添加 POI 的依赖,为了保持简洁,我们只添加 XSSF 的核心依赖。

<dependencies>
    <!-- 使用 XSSFWorkbook 操作 .xlsx 文件 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version> <!-- 建议使用最新稳定版 -->
    </dependency>
</dependencies>

基础示例:创建一个简单的 .xlsx 文件

这个例子将演示如何创建一个 Excel 文件,写入一些数据,并保存到本地。

目标: 创建一个名为 student.xlsx 的文件,包含一个工作表 "学生信息",表头有 "学号", "姓名", "年龄",并写入两条数据。

Java POI写入Excel如何操作?-图2
(图片来源网络,侵删)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
public class SimpleExcelWrite {
    public static void main(String[] args) {
        // 1. 创建一个新的工作簿 (XSSFWorkbook 对应 .xlsx 文件)
        Workbook workbook = new XSSFWorkbook();
        // 2. 在工作簿中创建一个工作表
        Sheet sheet = workbook.createSheet("学生信息");
        // 3. 创建行 (行号从 0 开始)
        // 创建表头行 (第 0 行)
        Row headerRow = sheet.createRow(0);
        // 4. 创建单元格并设置表头值
        headerRow.createCell(0).setCellValue("学号");
        headerRow.createCell(1).setCellValue("姓名");
        headerRow.createCell(2).setCellValue("年龄");
        // 5. 创建数据行
        Row dataRow1 = sheet.createRow(1);
        dataRow1.createCell(0).setCellValue(1001);
        dataRow1.createCell(1).setCellValue("张三");
        dataRow1.createCell(2).setCellValue(20);
        Row dataRow2 = sheet.createRow(2);
        dataRow2.createCell(0).setCellValue(1002);
        dataRow2.createCell(1).setCellValue("李四");
        dataRow2.createCell(2).setCellValue(21);
        // 6. 设置列宽,让内容显示更美观 (可选)
        sheet.autoSizeColumn(0); // 自动调整第一列宽度
        sheet.autoSizeColumn(1); // 自动调整第二列宽度
        sheet.autoSizeColumn(2); // 自动调整第三列宽度
        // 7. 定义输出文件路径
        String filePath = "D:/temp/student.xlsx";
        // 8. 将工作簿写入文件
        try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
            workbook.write(fileOut);
            System.out.println("Excel 文件生成成功!路径: " + filePath);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 9. 关闭工作簿,释放资源
            try {
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代码解释:

  1. Workbook workbook = new XSSFWorkbook();: 创建一个 .xlsx 格式的工作簿对象。
  2. Sheet sheet = workbook.createSheet("学生信息");: 在工作簿中创建一个名为 "学生信息" 的工作表。
  3. Row row = sheet.createRow(0);: 在工作表中创建一行,行号从 0 开始。0 代表第一行。
  4. Cell cell = row.createCell(0);: 在行中创建一个单元格,列号也从 0 开始。cell.setCellValue(...) 用于设置单元格的值。
  5. sheet.autoSizeColumn(0);: 自动调整指定列的宽度,以适应内容。
  6. try-with-resources: 使用 try (FileOutputStream ...) 可以确保 FileOutputStream 在代码块执行完毕后自动关闭,避免资源泄漏。
  7. workbook.close(): 关闭工作簿,释放内存,对于大型文件,这一步非常重要。

进阶示例:设置样式(字体、颜色、边框等)

在实际应用中,我们经常需要美化 Excel 表格,比如设置标题字体加粗、背景色、添加边框等。

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
public class StyledExcelWrite {
    public static void main(String[] args) {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("样式示例");
        // 1. 创建一个样式对象
        CellStyle headerStyle = workbook.createCellStyle();
        Font headerFont = workbook.createFont();
        // 2. 设置字体
        headerFont.setBold(true);            // 加粗
        headerFont.setFontHeightInPoints((short) 14); // 字号
        headerFont.setColor(IndexedColors.WHITE.getIndex()); // 字体颜色
        // 3. 将字体应用到样式
        headerStyle.setFont(headerFont);
        // 4. 设置背景色
        headerStyle.setFillForegroundColor(IndexedColors.BLUE.getIndex());
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        // 5. 设置边框
        headerStyle.setBorderTop(BorderStyle.THIN);
        headerStyle.setBorderBottom(BorderStyle.THIN);
        headerStyle.setBorderLeft(BorderStyle.THIN);
        headerStyle.setBorderRight(BorderStyle.THIN);
        // 6. 创建数据行样式
        CellStyle dataStyle = workbook.createCellStyle();
        dataStyle.setBorderTop(BorderStyle.THIN);
        dataStyle.setBorderBottom(BorderStyle.THIN);
        dataStyle.setBorderLeft(BorderStyle.THIN);
        dataStyle.setBorderRight(BorderStyle.THIN);
        // 7. 应用样式到表头行
        Row headerRow = sheet.createRow(0);
        String[] headers = {"产品名称", "销量", "单价"};
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
            cell.setCellStyle(headerStyle);
        }
        // 8. 应用样式到数据行
        Object[][] data = {
                {"苹果", 150, 5.5},
                {"香蕉", 200, 3.8},
                {"橙子", 180, 4.2}
        };
        for (int i = 0; i < data.length; i++) {
            Row row = sheet.createRow(i + 1);
            for (int j = 0; j < data[i].length; j++) {
                Cell cell = row.createCell(j);
                cell.setCellValue((Double) data[i][j]); // 假设数据都是数字
                cell.setCellStyle(dataStyle);
            }
        }
        // 9. 自动调整列宽
        for (int i = 0; i < headers.length; i++) {
            sheet.autoSizeColumn(i);
        }
        // 10. 写入文件
        String filePath = "D:/temp/styled_product.xlsx";
        try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
            workbook.write(fileOut);
            System.out.println("带样式的 Excel 文件生成成功!路径: " + filePath);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

关键点:

  • CellStyleFont: 样式和字体是分开创建的,一个 CellStyle 可以被多个 Cell 共享,这样可以提高性能。
  • IndexedColors: POI 提供了一个预定义的颜色常量枚举,方便使用。
  • FillPatternType: 设置填充模式,SOLID_FOREGROUND 表示纯色填充。

处理大数据量(SXSSF - 流式 API)

如果需要导出的数据量非常大(比如几十万行),使用 XSSFWorkbook 会导致内存溢出,因为它会将所有数据都加载到内存中。

Java POI写入Excel如何操作?-图3
(图片来源网络,侵删)

这时,你应该使用 SXSSF (Streaming Usermodel API),它的工作方式是:将一部分数据(比如100行)保存在内存中,当超过这个数量时,就会将它们临时写入磁盘(一个临时文件),从而释放内存,这个过程对用户是透明的。

SXSSFWorkbook 的核心参数:

  • rowAccessWindowSize: 内存中保留的行数,超过这个数量的行会被刷新到磁盘。100 是一个比较合理的默认值。

示例:使用 SXSSFWorkbook 导出 10 万条数据

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFRow;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
public class LargeDataExcelWrite {
    public static void main(String[] args) {
        // 1. 创建 SXSSFWorkbook,指定窗口大小为 100
        // -1 表示不使用基于行数的临时文件,而是基于内存使用量
        Workbook workbook = new SXSSFWorkbook(100); // 在内存中保留 100 行
        Sheet sheet = workbook.createSheet("大数据量示例");
        // 2. 创建表头 (和普通 XSSF 一样)
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("ID");
        headerRow.createCell(1).setCellValue("随机数");
        // 3. 创建大量数据
        System.out.println("开始生成数据...");
        Random random = new Random();
        for (int i = 1; i <= 100000; i++) {
            // 注意:SXSSF 的行创建方式略有不同,但通常可以直接使用 Row
            Row row = sheet.createRow(i);
            row.createCell(0).setCellValue(i);
            row.createCell(1).setCellValue(random.nextDouble() * 1000);
            // 每 10000 行打印一次进度
            if (i % 10000 == 0) {
                System.out.println("已生成 " + i + " 行数据...");
            }
        }
        // 4. 写入文件
        String filePath = "D:/temp/large_data.xlsx";
        try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
            workbook.write(fileOut);
            System.out.println("大数据量 Excel 文件生成成功!路径: " + filePath);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 5. 清理临时文件!非常重要!
            // SXSSFWorkbook 在关闭时会自动删除临时文件,但显式调用 cleanup() 更安全
            if (workbook instanceof SXSSFWorkbook) {
                ((SXSSFWorkbook) workbook).dispose();
            }
            try {
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

SXSSFWorkbook 的注意事项:

  1. rowAccessWindowSize: 这个参数是性能和内存消耗之间的权衡,值越大,性能越好,但内存消耗也越大。
  2. dispose(): 在 finally 块中调用 ((SXSSFWorkbook) workbook).dispose() 是一个好习惯,它会强制清理所有临时文件,确保没有遗留。
  3. 功能限制: SXSSFXSSF 的一个子集,不支持所有 XSSF 的功能,sheet.setRepeatingRows()sheet.setRepeatingColumns() 等。

写入 .xls 文件 (HSSFWorkbook)

如果你需要兼容旧版的 Excel (97-2003),使用 HSSFWorkbook 非常简单,只需替换几行代码即可。

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFCell;
// ... 其他 import 如 FileOutputStream, IOException ...
public class HssfExcelWrite {
    public static void main(String[] args) {
        // 1. 创建 HSSFWorkbook 对应 .xls 文件
        Workbook workbook = new HSSFWorkbook();
        // 2. 后续代码和 XSSF 几乎完全一样
        Sheet sheet = workbook.createSheet("HSSF 示例");
        Row row = sheet.createRow(0);
        row.createCell(0).setCellValue("Hello, HSSF!");
        String filePath = "D:/temp/hssf_example.xls";
        try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
            workbook.write(fileOut);
            System.out.println(".xls 文件生成成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

总结与建议

场景 推荐的 API 优点 缺点
新项目,数据量小 ( < 100,000 行) XSSFWorkbook 功能最全,API 成熟,易于使用 大数据量时内存消耗大,可能导致 OOM
新项目,数据量大 ( > 100,000 行) SXSSFWorkbook 内存占用低,可处理海量数据 功能受限,需要清理临时文件
需要兼容旧版 Excel (.xls) HSSFWorkbook 兼容性好 行列数限制 (65536x256),性能较差

最佳实践:

  1. 优先使用 XSSFWorkbook,除非你有特殊需求。
  2. 对于大数据导出,必须使用 SXSSFWorkbook
  3. 始终使用 try-with-resources 或在 finally 块中关闭 WorkbookFileOutputStream,以避免资源泄漏。
  4. 样式对象 (CellStyle, Font) 应该被复用,而不是为每个单元格都创建一个新的,这样可以显著提高性能和减少内存占用。
分享:
扫描分享到社交APP
上一篇
下一篇