简介
Apache POI是一个用于操作Microsoft Office格式文件(包括xls、docx、xlsx、pptx等)的Java API库。POI全称为Poor Obfuscation Implementation,是Apache Software Foundation的一个开源项目。它提供了一组Java API,使得Java程序可以读取、写入和操作Microsoft Office格式文件。
具体来说,POI提供了以下几种主要的组件:
HSSF:用于读写Excel 97-2003格式的xls文件。
XSSF:用于读写Excel 2007格式的xlsx文件。
SXSSF:是Apache POI中用于处理大量数据的API,它基于XSSF,可以处理Excel 2007及以上版本的xlsx文件。SXSSF的特点在于它可以将大量数据分成多个部分进行处理,从而减少内存的占用,提高处理大量数据的效率。
HWPF:用于读写Word 97-2003格式的doc文件。
XWPF:用于读写Word 2007格式的docx文件。
HSLF:用于读写PowerPoint 97-2003格式的ppt文件。
XSLF:用于读写PowerPoint 2007格式的pptx文件。
这里先介绍使用Apache POI 如何操作excel
环境准备
Maven仓库
jdk1.8
poi-3.9
poi-ooxml-3.9
poi-ooxml-schemas-3.9
xmlbeans-2.6.0
junit4.12
joda-time-2.10.1
写入Excel文件
Excel 97-2003 和 2007的区别?
文件格式不同:
Excel 97-2003使用的是 .xls格式,.xls格式采用二进制格式存储数据,
而Excel 2007使用的是 .xlsx格式。而.xlsx格式采用了基于XML的压缩文件格式。
大小限制不同:
Excel 97-2003的工作表大小限制为65536行、256列。
Excel 2007的工作表大小限制为1048576行、16384列。
API介绍
Workbook:表示一个Excel工作簿,包括多个Sheet,提供了创建Sheet、读取Sheet、写入Sheet等方法。
Sheet:表示一个Excel工作表,包括多个Row,提供了读取Row、写入Row、创建Cell等方法。
Row:表示Excel工作表中的一行,包括多个Cell,提供了读取Cell、写入Cell等方法。
Cell:表示Excel工作表中的一个单元格,提供了读取单元格值、写入单元格值、设置单元格样式等方法。
小文件写入
注意:代码中的 PATH 是声明的静态类变量,是基础的文件路径
static String PATH = "D:\\poi\\";
03版本-小文件写入
//03版本-小数据写入 @Test public void testWrite03() throws IOException { /** * 1.创建一个03版的工作簿 * HSSF-03版本 * XSSF=07版本 * SXSSF-加速处理07版本 */ Workbook workbook = new HSSFWorkbook(); /** * 2.创建一个工作表 * 通过工作簿来新建工作表,因为工作簿在工作表之上 */ Sheet sheet = workbook.createSheet("表1"); /** * 3.创建一个行 * 通过表创建行,因为表在行之上 * 0代表第一行 */ Row row1 = sheet.createRow(0); /** * 4.创建单元格 * 通过行创建单元格 */ Cell cell1_1 = row1.createCell(0);//第一行第一列 cell1_1.setCellValue("id"); Cell cell1_2 = row1.createCell(1);//第一行第二列 cell1_2.setCellValue("name"); Cell cell1_3 = row1.createCell(2);//第一行第三列 cell1_3.setCellValue("birth"); //第二行 Row row2 = sheet.createRow(1); Cell cell2_1 = row2.createCell(0);//第二行第一列 cell2_1.setCellValue(1); Cell cell2_2 = row2.createCell(1);//第二行第二列 cell2_2.setCellValue("嘴哥"); Cell cell2_3 = row2.createCell(2);//第一行第三列 //使用 joda包创建时间 String time = new DateTime().toString("yyyy-MM-dd"); cell2_3.setCellValue(time); //生成一张表 03版本用 xls 结尾 File file = new File(PATH+"03_1.xls"); FileOutputStream outputStream = new FileOutputStream(file); //输出到本地 workbook.write(outputStream); //关闭流 outputStream.close(); System.out.println("文件生成完毕!"); }
运行结果
07版本-小文件写入
//07版本-小数据写入 @Test public void testWrite07() throws IOException { /** * 1.创建一个03版的工作簿 * HSSF-03版本 * XSSF=07版本 * SXSSF-加速处理07版本 */ Workbook workbook = new XSSFWorkbook(); /** * 2.创建一个工作表 * 通过工作簿来新建工作表,因为工作簿在工作表之上 */ Sheet sheet = workbook.createSheet("表1"); /** * 3.创建一个行 * 通过表创建行,因为表在行之上 * 0代表第一行 */ Row row1 = sheet.createRow(0); /** * 4.创建单元格 * 通过行创建单元格 */ Cell cell1_1 = row1.createCell(0);//第一行第一列 cell1_1.setCellValue("id"); Cell cell1_2 = row1.createCell(1);//第一行第二列 cell1_2.setCellValue("name"); Cell cell1_3 = row1.createCell(2);//第一行第三列 cell1_3.setCellValue("birth"); //第二行 Row row2 = sheet.createRow(1); Cell cell2_1 = row2.createCell(0);//第二行第一列 cell2_1.setCellValue(1); Cell cell2_2 = row2.createCell(1);//第二行第二列 cell2_2.setCellValue("嘴哥"); Cell cell2_3 = row2.createCell(2);//第一行第三列 //使用 joda包创建时间 String time = new DateTime().toString("yyyy-MM-dd"); cell2_3.setCellValue(time); //生成一张表 03版本用 xls 结尾 File file = new File(PATH+"03_1.xlsx"); FileOutputStream outputStream = new FileOutputStream(file); //输出到本地 workbook.write(outputStream); //关闭流 outputStream.close(); System.out.println("文件生成完毕!"); }
运行结果
大文件写入
03版本-大文件写入
//03版本-大数据写入65536行 1400ms @Test public void testWrite03BigData() throws IOException { //开始时间 long begin = System.currentTimeMillis(); //创建一个工作簿 Workbook workbook = new HSSFWorkbook(); //创建表 Sheet sheet = workbook.createSheet(); //写入数据 for (int rowNums = 0; rowNums < 65536; rowNums++) { Row row = sheet.createRow(rowNums); for (int cellNums = 0; cellNums < 10; cellNums++) { Cell cell = row.createCell(cellNums); cell.setCellValue(cellNums); } } System.out.println("over"); FileOutputStream outputStream = new FileOutputStream(new File(PATH + "bigData03.xls")); workbook.write(outputStream); outputStream.close(); //结束时间 long end = System.currentTimeMillis(); System.out.println("总用时 "+(end-begin)+"ms"); }
07版本-大文件写入
//07版本-大数据写入65537行 6856ms @Test public void testWrite07BigData() throws IOException { //开始时间 long begin = System.currentTimeMillis(); //创建一个工作簿 Workbook workbook = new XSSFWorkbook(); //创建表 Sheet sheet = workbook.createSheet(); //写入数据 for (int rowNums = 0; rowNums < 65537; rowNums++) { Row row = sheet.createRow(rowNums); for (int cellNums = 0; cellNums < 10; cellNums++) { Cell cell = row.createCell(cellNums); cell.setCellValue(cellNums); } } System.out.println("over"); FileOutputStream outputStream = new FileOutputStream(new File(PATH + "bigData03.xlsx")); workbook.write(outputStream); outputStream.close(); //结束时间 long end = System.currentTimeMillis(); System.out.println("总用时 "+(end-begin)+"ms"); }
运行结果
07升级版-大文件写入
//07升级版-大数据写入10w行 1814ms @Test public void testWrite07BigDataS() throws IOException { //开始时间 long begin = System.currentTimeMillis(); //创建一个工作簿 Workbook workbook = new SXSSFWorkbook(); //创建表 Sheet sheet = workbook.createSheet(); //写入数据 for (int rowNums = 0; rowNums < 100000; rowNums++) { Row row = sheet.createRow(rowNums); for (int cellNums = 0; cellNums < 10; cellNums++) { Cell cell = row.createCell(cellNums); cell.setCellValue(cellNums); } } System.out.println("over"); FileOutputStream outputStream = new FileOutputStream(new File(PATH + "bigData03S.xlsx")); workbook.write(outputStream); //关闭资源 outputStream.close(); //关闭临时文件 ((SXSSFWorkbook)workbook).dispose(); //结束时间 long end = System.currentTimeMillis(); System.out.println("总用时 "+(end-begin)+"ms"); }
总结
HSSF:适用于读写Excel 97-2003格式的xls文件,可以处理一般大小的数据,缺点是处理大量数据时,会占用大量内存,导致程序运行较慢。
XSSF:适用于读写Excel 2007及以上版本的xlsx文件,支持更多的行列数、更好的样式支持等,但处理大量数据时,仍然会占用大量内存,不适合处理大数据量的情况。
SXSSF:基于XSSF,适用于处理大量数据,可以将大量数据分成多个部分进行处理,从而减少内存的占用,提高处理大量数据的效率。但不支持公式计算等高级功能。
综上,选择API应根据具体的需求和数据量来决定。如果处理的数据量较小,可以选择HSSF或XSSF;如果需要处理大量数据,可以选择SXSSF。如果需要同时兼顾处理大量数据和高级功能,可以考虑使用HSSF或XSSF与SXSSF结合的方式来处理数据。
03版-文件读取
@Test public void testRead03() throws IOException { //获取文件流 FileInputStream inputStream = new FileInputStream(new File(PATH+"03_1.xls")); //1.创建一个工作簿,使用excel能操作的,它都可以操作 Workbook workbook = new HSSFWorkbook(inputStream); //2.获取表 Sheet sheet0 = workbook.getSheetAt(0); //3.得到行 Row row = sheet0.getRow(1);//获取第1行 //4.得到列 Cell cell = row.getCell(0);//获取第一行第一列 //以Number形式输出-可以选择格式 //必须对应格式-number类型不可以转为String类型!! System.out.println(cell.getNumericCellValue()); //关闭流资源 inputStream.close(); }
07版本-文件读取
@Test public void testRead07() throws IOException { //获取文件流 FileInputStream inputStream = new FileInputStream(new File(PATH+"03_1.xlsx")); //1.创建一个工作簿,使用excel能操作的,它都可以操作 Workbook workbook = new XSSFWorkbook(inputStream); //2.获取表 Sheet sheet0 = workbook.getSheetAt(0); //3.得到行 Row row = sheet0.getRow(1);//获取第1行 //4.得到列 Cell cell = row.getCell(0);//获取第一行第一列 //以Number形式输出-可以选择格式 //必须对应格式-number类型不可以转为String类型!! System.out.println(cell.getNumericCellValue()); //关闭流资源 inputStream.close(); }
不同类型数据的读取
针对字符串、数值类型、日期等需要不同的处理方式。
//测试读取不同类型的数据 03版本 @Test public void testCellType() throws IOException { FileInputStream inputStream = new FileInputStream(new File(PATH+"test03.xls")); Workbook workbook = new HSSFWorkbook(inputStream); Sheet sheet = workbook.getSheetAt(0); //读取标题内容 Row title = sheet.getRow(0); if (title != null){ int columns = title.getPhysicalNumberOfCells();//列数 for (int cellNum = 0; cellNum < columns; cellNum++) { Cell cell = title.getCell(cellNum); if (cell != null){ int cellType = cell.getCellType();//我们已知为String String cellValue = cell.getStringCellValue(); System.out.print(cellValue+" | "); } } System.out.println(); } //读取表中的内容 int rows = sheet.getPhysicalNumberOfRows();//行数 for (int rowNum = 1; rowNum < rows; rowNum++) { Row row = sheet.getRow(rowNum); if (row != null){ //读取行中的列 int columns = title.getPhysicalNumberOfCells(); for (int col = 0; col < columns; col++) { System.out.print("["+(rowNum+1)+"-"+(col+1)+"]"); Cell cell = row.getCell(col); //匹配列的数据类型 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_NUMERIC://数字(日期、数字) if (HSSFDateUtil.isCellDateFormatted(cell)){//日期 System.out.print("[DATE]"); Date date = cell.getDateCellValue(); cellValue = new DateTime(date).toString("yyyy-MM-dd"); }else{ System.out.print("[NUMBER]"); //防止数字过长,转为String cell.setCellType(HSSFCell.CELL_TYPE_STRING); cellValue = cell.toString(); } break; case HSSFCell.CELL_TYPE_BLANK://空 System.out.print("[NULL]"); break; case HSSFCell.CELL_TYPE_BOOLEAN://布尔 System.out.print("[BOOLEAN]"); cellValue = String.valueOf(cell.getBooleanCellValue()); case HSSFCell.CELL_TYPE_ERROR: System.out.print("[ERROR]"); cellValue = String.valueOf(cell.getErrorCellValue()); break; } System.out.println(cellValue); } } } } inputStream.close(); }