本文最后更新于:2023年11月9日 晚上
本篇文章将讲述使用POI如何去对Excel文件进行读写
apache的POI文档:https://poi.apache.org
1.Maven导入poi包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <!--导入依赖--> <dependencies> <!--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>
<!--日期格式化工具--> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10.1</version> </dependency>
<!--junit测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
|
这里解释下为什么有两个版本(03版,07版) ?
1. 两者的文件后缀不同,03版本是.xls,07版本是.xlsx
2. 03版的最多只能有65536行 (03版本如果写入数据超过65536行,则会出现异常),而07版行数可以无限制 (代表07版可以存放的数据更多)
在开始代码之前,先认识下Excel表结构 直接看下图
/1.png)
2.POI进行基本的写入
注:03版本使用 HSSFWorkbook,07版本使用 XSSFWorkbook (07版本大量数据写入使用SXSSFWorkbook)
07版本的XSSFWorkbook 与 SXSSFWorkbook的区别 ?这个疑问下面会讲到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.Test;
import java.io.FileOutputStream;
public class test {
final String PATH = "D:\\IntelliJ IDEA 2019.1_File\\POIandEasyExcel\\poi\\";
@Test public void poi03() throws Exception { Workbook workbook = new HSSFWorkbook(); Sheet sheet = workbook.createSheet("03版本"); Row row = sheet.createRow(0); Cell cell = row.createCell(0); cell.setCellValue("第一行第一列"); Cell cell2 = row.createCell(1); cell2.setCellValue("第一行第二列"); Row row2 = sheet.createRow(1); Cell cell21 = row2.createCell(0); cell21.setCellValue("第二行第一列"); Cell cell22 = row2.createCell(1); cell22.setCellValue("第二行第二列");
FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03Excel.xls"); workbook.write(fileOutputStream); fileOutputStream.close(); }
@Test public void poi07() throws Exception { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("07版本"); Row row = sheet.createRow(0); Cell cell = row.createCell(0); cell.setCellValue("第一行第一列"); Cell cell2 = row.createCell(1); cell2.setCellValue("第一行第二列"); Row row2 = sheet.createRow(1); Cell cell21 = row2.createCell(0); cell21.setCellValue("第二行第一列"); Cell cell22 = row2.createCell(1); cell22.setCellValue("第二行第二列");
FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07Excel.xlsx"); workbook.write(fileOutputStream); fileOutputStream.close(); } }
|
3.POI进行大量数据的写入
模拟下大量数据的写入,写入65536行,10列(每行10个单元格)的数据
并且记录程序所耗费的时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| @Test public void poi03BigDate() throws Exception {
long begin = System.currentTimeMillis();
Workbook workbook = new HSSFWorkbook(); Sheet sheet = workbook.createSheet("03版本大量数据写入");
for (int x = 0; x < 65536; x++) { Row row = sheet.createRow(x); for (int y = 0; y < 10; y++) { Cell cell = row.createCell(y); cell.setCellValue(y); } }
FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03BIgDate.xls"); workbook.write(fileOutputStream); fileOutputStream.close();
long end = System.currentTimeMillis();
System.out.println("HSSF_03版耗时:" + (double) (end - begin) / 1000); }
@Test public void poi07BigDate() throws Exception {
long begin = System.currentTimeMillis();
Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("07版本大量数据写入");
for (int x = 0; x < 65536; x++) { Row row = sheet.createRow(x); for (int y = 0; y < 10; y++) { Cell cell = row.createCell(y); cell.setCellValue(y); } }
FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07BIgDate.xlsx"); workbook.write(fileOutputStream); fileOutputStream.close();
long end = System.currentTimeMillis();
System.out.println("XSSF_07版耗时:" + (double) (end - begin) / 1000); }
|
03版如果写入超过65536行数据则会出现异常(这就是03版与07版很大的区别,还有就是后缀名不同,03版本是 .xls,07版本是 .xlsx):
/2.png)
03版HSSF耗时:
优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快
缺点:只能操作65536行数据,否则会抛出异常
(java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535))
/3.png)
07版XSSF耗时:
优点:可以写非常大的数据量,比如几十万
缺点:写数据时非常慢,很耗内存,所有很有可能发生内存溢出(OOM)
/4.png)
07版SXSSF耗时(07版本将 XSSFWorkbook对象 替换为 SXSSFWorkbook 对象):
优点:在写入庞大数据量时,耗时更少,占用更少的内存
注意:在写入数据时,有一部分会被先写到临时文件,执行完之后需要清理临时文件。如果想自定义内存中的数量可以 new SXSSFWorkbook(传入数量)
/5.png)
Excel写入总结:
4. POI读取数据 (模拟两个案例)
注:
1. 此案例只是03版本的Excel (如果是07版的Excel 换掉工作簿的对象即可,将HSSFWorkbook 变为XSSFWorkbook)
** 2. 读取数据最复杂得点在于 转换Excel表中数据。比如日期、数字、小数、字符串、Excel中得函数公式、空单元格**
** 3. 所以可以使用 switch case 对不同类型进行判断 匹配**
案例一:
下面有一个Excel表,把其中数据取出来,到控制台输出(都到控制台了,还不能存入数据库吗?):
/6.png)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| @Test public void poi03read() throws Exception {
FileInputStream FileInputStream = new FileInputStream(PATH + "会员消费商品明细表.xls");
Workbook workbook = new HSSFWorkbook(FileInputStream);
Sheet sheetAt = workbook.getSheetAt(0);
int rowCount = sheetAt.getPhysicalNumberOfRows();
for (int rowNum = 0; rowNum < rowCount; rowNum++) { Row row = sheetAt.getRow(rowNum);
if (row != null) {
int cellCount = row.getPhysicalNumberOfCells();
for (int cellNum = 0; cellNum < cellCount; cellNum++) {
Cell cell = row.getCell(cellNum);
if (cell != null) { int cellType = cell.getCellType();
String cellValue = "";
switch (cellType) { case Cell.CELL_TYPE_STRING: cellValue = cell.getStringCellValue(); System.out.print(cellValue + " "); break;
case Cell.CELL_TYPE_BOOLEAN: cellValue = String.valueOf(cell.getBooleanCellValue()); System.out.print(cellValue + " "); break;
case Cell.CELL_TYPE_NUMERIC: if (HSSFDateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); cellValue = new DateTime(date).toString("yyyy-MM-dd"); System.out.print(cellValue); } else { cell.setCellType(Cell.CELL_TYPE_STRING); cellValue = cell.getStringCellValue(); System.out.print(cellValue + " "); } break;
case Cell.CELL_TYPE_ERROR: break;
case Cell.CELL_TYPE_BLANK: break; } } } } System.out.println(); } FileInputStream.close(); }
|
案例二:
下面有一个Excel表,把它读取出来,到控制台输出(获得总和值和单元格中得函数公式):
/7.png)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| @Test public void poi03readFormula() throws Exception {
FileInputStream FileInputStream = new FileInputStream(PATH + "计算公式.xls");
Workbook workbook = new HSSFWorkbook(FileInputStream);
Sheet sheetAt = workbook.getSheetAt(0);
int rowCount = sheetAt.getPhysicalNumberOfRows();
for (int rowNum = 0; rowNum < rowCount; rowNum++) { Row row = sheetAt.getRow(rowNum); if (row != null) { int cellCount = row.getPhysicalNumberOfCells(); for (int cellNum = 0; cellNum < cellCount; cellNum++) { Cell cell = row.getCell(cellNum); if (cell != null) { int cellType = cell.getCellType(); String cellValue = ""; switch (cellType) { case Cell.CELL_TYPE_FORMULA:
cell.setCellType(Cell.CELL_TYPE_FORMULA);
String formula = cell.getCellFormula();
System.out.println(formula);
FormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);
CellValue evaluate = formulaEvaluator.evaluate(cell);
cellValue = evaluate.formatAsString();
System.out.println(cellValue); break; } } } } } FileInputStream.close(); }
|
因为回忆太痛苦,所有我们要一直往前走。