POI技术

本文介绍了Apache POI用于Java操作Excel的基础与高级用法,包括03/07版本读写示例,以及阿里巴巴EasyExcel的高效Excel处理框架。通过实例展示了如何利用这些工具进行数据读写和业务逻辑处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是POI

Apache POI 是用java编写的免费开源的JAVA API,Apach POI提供了API给Java 程式对 Microsoft Office(Excel、WORD、PowerPoint、Visio 等,主要实现用于 Excel)格式档案读和写的功能,POI 为 “ Poor Obfuscation Implementation ” 的首字母缩写,意为“简洁版的模糊实现”。

简单来说就是使用java来对excel文件进行读写操作,POI提供了java操作excel等文件的API。

二、Apache POI的使用

  1. 导入相应依赖,因为excel有两个版本,一个是03版本.xls,一个是07版本.xlsx:
<!--xls(03)-->
<dependency>
     <groupId>org.apache.poi</groupId>
     <artifactId>poi</artifactId>
    <version>3.9</version>
</dependency>
<!--xlsx(07)-->
<dependency>
     <groupId>org.apache.poi</groupId>
     <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
</dependency>

  1. 进行相关API测试,主要分为对Excel文件的读和写,全在代码里了
public class ExcelTest {

    // 记录下项目根路径,为方便后面拼接文件路径
    String Path = "D:\\IdeaProjects\\testdemo\\poi_demo\\";


    @Test //03版本,写入测试
    public void testWrite03() throws Exception{

        // 1. 创建工作簿(也就是excel文件)
        Workbook workbook = new HSSFWorkbook(); //03版本的excel,03版本最大支持65536行数据     xxx.xls
        //Workbook workbook = new XSSFWorkbook(); // 07版本的excel,07版本没有限制   xxx.xlsx

        // 2. 创建表(也就是excel文件中左下角的sheet表)
        Sheet sheet = workbook.createSheet("统计表01");

        // 3. 根据表,创建行
        Row row = sheet.createRow(0);

        // 4. 根据行,创建单元格  (其实就是坐标,注意一定是先有行,再有列。根据行创建唯一的单元格)
        Cell cell1 = row.createCell(0);
        cell1.setCellValue("球队");
        Cell cell2 = row.createCell(1);
        cell2.setCellValue("球员");

        // 重复上的操作,再创建一行
        Row row1 = sheet.createRow(1);
        Cell cell = row1.createCell(0);
        cell.setCellValue("太阳");
        Cell cell3 = row1.createCell(1);
        cell3.setCellValue("保罗");

        // 新建文件输出流
        FileOutputStream fos = new FileOutputStream(Path + "NBA统计表.xls");
        // 将设置好的工作簿,写入磁盘
        workbook.write(fos);

        fos.close();//关闭流

        System.out.println("文件生成成功!");


    }

    @Test  // 07版本,写入测试
    public void testWrite07BigData() throws Exception{

        long begin = System.currentTimeMillis();

        //Workbook workbook = new XSSFWorkbook();// 创建07版本的Excel
        Workbook workbook = new SXSSFWorkbook(); // 创建07版本的快速写入实现类

        Sheet sheet = workbook.createSheet();

        for (int i = 0; i < 100000 ; i++) { // 07版本行数无限制,所以创建个大于65536行的表

            Row row = sheet.createRow(i);
            for (int j = 0; j < 5; j++) { // 每行写5个数据
                Cell cell = row.createCell(j);
                cell.setCellValue(i+","+j);
            }

        }

        FileOutputStream fos = new FileOutputStream(Path+"观众数量统计表.xlsx");
        workbook.write(fos);
        fos.close();

        // 清除临时文件
        ((SXSSFWorkbook)workbook).dispose();

        long end = System.currentTimeMillis();

        // 经测试发现:
        // 普通07版本XSSFWorkbook,耗时50秒
        // 快速版本SXSSFWorkbook,耗时6秒,速度提升近10倍
        System.out.println("写入文件完成,共耗时:"+(end-begin)/1000+" 秒");
    }

    @Test // 测试 03、07版本  读
    public void testRead03() throws Exception{

        FileInputStream fis = new FileInputStream(Path+"NBA统计表.xls");

        // 读取工作簿
        Workbook workbook = new HSSFWorkbook(fis);
        //Workbook workbook = new XSSFWorkbook(fis);  07版本就实现类不同而已

        // 获取第一个表
        Sheet sheet = workbook.getSheetAt(0);

        // 获取第一行第一列的单元格
        Row row = sheet.getRow(0);
        Cell cell = row.getCell(0);

        // 输入单元格内容
        System.out.println(cell.getStringCellValue());

        fis.close();
    }

    @Test // 在工作中,一个excel中会有很多数据类型,所以在读的时候就要加各种判断类型的逻辑
    public void testCellType() throws Exception{

        InputStream is = new FileInputStream(Path+"会员消费商品明细表.xls");
        Workbook workbook = new HSSFWorkbook(is);

        Sheet sheet = workbook.getSheetAt(0);

        // 读取第一行表头数据
        Row row = sheet.getRow(0);
        if(row!=null){
            int cellCount = row.getPhysicalNumberOfCells();// 获取改行的长度

            for (int i = 0; i <cellCount ; i++) {
                Cell cell = row.getCell(i);
                if(cell!=null){
                    String cellValue = cell.getStringCellValue();// 因为第一行一般都是表头,所以直接用String类型来接收了
                    System.out.print(cellValue+"|");
                }
            }
            System.out.println();//换行
        }

        // 读取商品列表数据
        int rowCount = sheet.getPhysicalNumberOfRows();//获取该sheet有几行
        for (int i = 1; i <rowCount ; i++) { // 第一行已经获取过了,所以从第二行开始读取数据

            Row rowData = sheet.getRow(i);
            if(rowData!=null){

                int cellCount = rowData.getPhysicalNumberOfCells();//获取该行共有几列

                for (int j = 0; j < cellCount; j++) {

                    Cell cell = rowData.getCell(j);
                    if(cell!=null){

                        int cellType = cell.getCellType();//获取单元格数据类型

                        String cellValue = "";
                        switch (cellType) {

                            case HSSFCell.CELL_TYPE_STRING://字符串
								System.out.print("【STRING】");
								cellValue = cell.getStringCellValue();
								break;

							case HSSFCell.CELL_TYPE_BOOLEAN://布尔
								System.out.print("【BOOLEAN】");
								cellValue = String.valueOf(cell.getBooleanCellValue());
								break;

							case HSSFCell.CELL_TYPE_BLANK://空
								System.out.print("【BLANK】");
								break;

							case HSSFCell.CELL_TYPE_NUMERIC:
								System.out.print("【NUMERIC】");
								//cellValue = String.valueOf(cell.getNumericCellValue());

								if (HSSFDateUtil.isCellDateFormatted(cell)) {//日期
									System.out.print("【日期】");
									Date date = cell.getDateCellValue();
									cellValue = new DateTime(date).toString("yyyy-MM-dd");
								} else {
									// 不是日期格式,则防止当数字过长时以科学计数法显示
									System.out.print("【转换成字符串】");
									cell.setCellType(HSSFCell.CELL_TYPE_STRING);
									cellValue = cell.toString();
								}
								break;

							case Cell.CELL_TYPE_ERROR:
								System.out.print("【数据类型错误】");
								break;


                        }
							System.out.println(cellValue);

                    }
                }
            }
        }
       
        is.close();

    }
}

三、EasyExcel框架

EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单,节省内存著称,EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。

下面是使用EasyExcel的代码示例:

  1. 创建一个实体类
@Data
public class BasketballPlayer {

    // @ExcelProperty 将实体类中字段和Excel中的标题互相绑定

    @ExcelProperty("球员")
    private String name;

    @ExcelProperty("数字")
    private Integer number;

    @ExcelProperty("球队")
    private String team;

    @ExcelProperty("生日")
    private Date Birthday;

    /**
     * ExcelIgnore 可以用来设置所要忽略的字段
     */
    @ExcelIgnore
    private String ignore;
}
  1. 创建针对此实体类的一个监听器
// 有个很重要的点 BasketballListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class BasketballListener extends AnalysisEventListener<BasketballPlayer> {

    @Override
    public void invoke(BasketballPlayer basketballPlayer, AnalysisContext analysisContext) {
        System.out.println("====invoke方法执行,每读到一行数据就会走一次这个方法===");

        //这里的basketballPlayer就是excel中的数据,已经自动从excel中读取并封装到该实体类中了
        System.out.println(basketballPlayer.toString());

        System.out.println("这里可以进行一些逻辑处理,或者保存到数据库,等操作都可以进行");
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        System.out.println("====整个sheet读完之后,doAfterAllAnalysed方法执行===");
    }
}
  1. 使用EasyExcel进行读写测试
public class EasyExcelTest {

    String path = "D:\\IdeaProjects\\testdemo\\poi_demo\\";

    @Test
    public void testRead(){

        String filePath = path +"NBA球员信息表.xlsx";

        EasyExcel.read(filePath, BasketballPlayer.class, new BasketballListener()).sheet().doRead();

    }

    @Test
    public void testWrite(){

        String filePath = path +"NBA统计表.xls";

        EasyExcel.write(filePath,BasketballPlayer.class).sheet("模板1").doWrite(data());

    }

    // 模拟要写入excel的数据
    private List<BasketballPlayer> data() {
        List<BasketballPlayer> list = new ArrayList<BasketballPlayer>();
        for (int i = 0; i < 10; i++) {
            BasketballPlayer data = new BasketballPlayer();
            data.setName("詹姆斯"+i+"号");
            data.setNumber(i);
            data.setTeam("球队"+i);
            data.setBirthday(new Date());
            list.add(data);
        }
        return list;
    }
}

从上面的示例中可以看到,使用EasyExcel几乎一行代码就可以完成对Excel的读写操作,而且他帮我们完成了excel数据封装到实体类这一步,且我们只需要在listener中写自己的业务逻辑即可。

不过上面的示例代码只是最简单的EasyExcel的使用,真正到开发中使用的话还需要根据具体的需求来具体应用。

EasyExcel官网上有具体的使用文档:EasyExcel官网地址

<think>好的,我现在要处理用户关于Apache POI技术文档和使用教程的请求。首先,我需要确认用户的具体需求是什么。用户提到想了解或使用POI技术,特别是Apache POI技术文档或使用教程。根据用户提供的参考引用,用户可能已经看过一些基础内容,但需要更详细的信息。 接下来,我需要回顾Apache POI的基本结构和组件。根据引用[1]和[2],Apache POI是用于操作Microsoft文档的Java API,支持Word、Excel等。用户可能想知道如何开始使用它,比如如何创建和编辑Word文档,以及可能的高级操作。 我需要确保回答符合系统级指令,比如使用正确的中文,数学表达式用$...$,独立公式用$$...$$,并且生成相关问题。同时,引用标识要正确添加到引用段落末尾。 首先,组织回答结构。用户需要技术文档或教程,所以应该分步骤介绍,可能包括环境配置、基本操作、示例代码等。参考引用中提到创建Word文档的基本步骤和结构分析,这部分内容需要详细说明。 然后,要检查是否有必要提到其他组件,比如处理Excel的HSSF和XSSF,但用户主要关注Word文档,所以可能需要侧重HWPF和XWPF。同时,要确保代码示例正确,并符合用户提到的Python示例格式,不过Apache POIJava库,所以需要提供Java代码示例。 另外,用户可能遇到的常见问题,比如文档结构处理、格式设置、性能优化等,也需要在相关问题中提及。需要确保生成的相关问题能够覆盖用户可能的后续疑问,比如性能优化、高级功能、错误处理等。 最后,验证所有引用是否正确添加,比如引用[^1]和[^2]是否对应到用户提供的参考内容,并确保回答中没有使用Markdown格式,保持自然的中文叙述。</think>### Apache POI 技术文档与使用教程 Apache POI 是用于操作 Microsoft Office 格式文件(如 Word、Excel)的 Java API,支持文档的创建、读取、修改和格式化[^1]。以下是其核心功能和使用方法: --- #### 一、Apache POI 核心组件 1. **HWPF/XWPF**:处理 Word 文档(.doc 和 .docx 格式) - `HWPF` 用于旧版 `.doc` 文件,`XWPF` 支持新版 `.docx`。 2. **HSSF/XSSF**:处理 Excel 表格(.xls 和 .xlsx 格式) 3. **HSLF/XSLF**:操作 PowerPoint 演示文稿 --- #### 二、Word 文档创建基础步骤 1. **环境配置** - Maven 依赖: ```xml <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> ``` 2. **创建文档与段落** ```java import org.apache.poi.xwpf.usermodel.*; public class CreateWordDoc { public static void main(String[] args) throws Exception { XWPFDocument document = new XWPFDocument(); // 创建空文档 XWPFParagraph paragraph = document.createParagraph(); // 添加段落 XWPFRun run = paragraph.createRun(); // 段落文本块 run.setText("Hello, Apache POI!"); document.write(new FileOutputStream("example.docx")); document.close(); } } ``` 3. **格式设置** - 字体样式:`run.setBold(true); run.setFontSize(14);` - 段落对齐:`paragraph.setAlignment(ParagraphAlignment.CENTER);` --- #### 三、高级操作示例 1. **表格插入** ```java XWPFTable table = document.createTable(2, 3); // 2行3列 table.getRow(0).getCell(0).setText("Header 1"); table.getRow(1).getCell(0).setText("Data 1"); ``` 2. **图片嵌入** ```java FileInputStream image = new FileInputStream("logo.png"); run.addPicture(image, Document.PICTURE_TYPE_PNG, "logo.png", Units.toEMU(200), Units.toEMU(100)); ``` --- #### 四、技术文档资源 1. **官方文档**: [Apache POI 官网](https://poi.apache.org/) 提供完整的 API 说明与示例。 2. **教程推荐**: - 《Apache POI Cookbook》详解常见操作场景 - GitHub 开源项目 `poi-examples` 提供可直接运行的代码模板[^2]。 --- §§ 1. 如何处理 Word 文档中的复杂格式(如页眉、页脚)? 2. Apache POI 在读写大型 Excel 文件时如何优化性能? 3. 如何解决 POI 与不同 Office 版本兼容性问题? 4. 是否支持将 HTML 转换为 Word 文档? : Apache POI - the Java API for Microsoft Documents : Apache POI 不仅使 Word 文档操作变得简单,还为高级操作提供了足够的灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值