几个月以前找工作时我收到了人生中第一份为了竞争工作的笔试题。打开的时候还是很期待的,但是打开后我发现,里面竟然只有一道题。让我用程序来将他发给我的一个数据量很大的excel表格读取并按照他要求的几列来进行分类,同一类的数据保存到同一个文件中。说实话我当时并没有学过POI,甚至根本还不知道这个东西。去问了身边一些认识的人,他们说你直接放弃吧,公司那么多,谁会这个啊。但由于有些不甘心,去问了我的老师。老师说:“你去学吧,这个叫POI。”于是,我就去现学现卖了......最终成功通过了笔试和两轮面试,获得了这家公司的offer~
这段时间我又做到了涉及到java中POI的需求,所以决定把这个整理一下。其实这个api和操作过程很简单,难得往往是我们在开发中如何合理的运用,以及我们自己的逻辑思维。
Apache POI 是基于Office Open XML 标准(OOXML)和 Microsoft 的OLE 2 复合文档格式(OLE2)处理各种文件格式的开源项目。简而言之,您可以使用Java读写MS Excel文件,可以使用Java读写MS Word 和 MS PowerPoint 文件。
目录
模块
-
HSSF - 提供读写 Microsoft Excel XLS 格式 (Microsoft Excel 97 (-2003)) 档案的功能。
-
XSSF - 提供读写 Microsoft Excel OOXML XLSX 格式 (Microsoft Excel XML (2007+)) 档案的功能。
-
SXSSF - 提供低内存占用量读写 Microsoft Excel OOXML XLSX 格式档案的功能。
-
HWPF - 提供读写 Microsoft Word DOC97 格式 (Microsoft Word 97 (-2003)) 档案的功能。
-
XWPF - 提供读写 Microsoft Word DOC2003 格式 (WordprocessingML (2007+)) 档案的功能。
-
HSLF/XSLF - 提供读写 Microsoft PowerPoint 格式档案的功能。
-
HDGF/XDGF - 提供读 Microsoft Visio 格式档案的功能。
-
HPBF - 提供读 Microsoft Publisher 格式档案的功能。
-
HSMF - 提供读 Microsoft Outlook 格式档案的功能。
Maven依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
文件类型有很多种,不同的文件类型我们需要使用不同的类来进行操作,如Excel格式我们就要用到HSSFWorkboo。其实学会一个其他的自然就会了,下面我就用Excel为例子:
Excel写操作
先给大家介绍一下我们Excel文件的结构:
public static void excelWrite() throws Exception{
String path = "/Users/admin/Desktop/list/";
//创建一个工作簿
Workbook workbook = new HSSFWorkbook();
//创建一个工作表
Sheet sheet = workbook.createSheet("页面访问统计表");
//创建一个行 第i行的下标为i-1
Row row1 = sheet.createRow(0);
//创建一个单元格 第i列的单元格的下标i-1 (1,1)
Cell cell11 = row1.createCell(0);
cell11.setCellValue("今日访客量");
//(1,2)
Cell cell12 = row1.createCell(1);
cell12.setCellValue(666);
Row row2 = sheet.createRow(1);
//(2,1)
Cell cell21 = row2.createCell(0);
cell21.setCellValue("页面类型");
//(2,2)
Cell cell22 = row2.createCell(1);
cell22.setCellValue("购物");
FileOutputStream fileOutputStream = new FileOutputStream(path + "页面访问统计表.xls");
workbook.write(fileOutputStream);
//关闭流
fileOutputStream.close();
workbook.close();
System.out.println("生成完成");
}
在main函数中调用一下
public static void main(String[] args) throws Exception{
ExampleUtil.excelWrite();
}
就可以生成一个excel文件存储在我们指定的路径:
SXSSF
HSSF用来对Microsoft Excel XLS 格式进行读写操作,仅能保存65536行数据,而对Microsoft Excel OOXML XLSX 格式 (Microsoft Excel XML (2007+))进行读写的话需要用XSSF,虽然XSSF没有限制,但是它的速度很慢,所以我们可以用速度快且占用内存少的SXSSF。
SXSSF会产生临时文件。它默认在内存中保存的记录条数为100,如果超过这个数量,则行号(rownum)最小的数据将被写入临时文件中,可以通过使用它的有参构造SXSSFWorkbook(int windowSize)来对整个工作簿存放在内存中的记录条数进行修改,还可以通过setRandomAccessWindowSize(int windowSize)对单个表在内存中的记录条数进行修改。需要注意的是你必须通过调用dispose方法来清理定时文件。
有关于SXSSF的工作原理可以查看官网:
public static void SXSSFWrite() throws Exception{
String path = "/Users/admin/Desktop/list/";
//创建一个工作簿 为他设定windowSize
Workbook workbook = new SXSSFWorkbook(100);
//创建一个工作表
Sheet sheet = workbook.createSheet("页面访问数据表");
//为单个表设置windowSize
((SXSSFSheet)sheet).setRandomAccessWindowSize(110);
//写入数据
for (int rowNum = 0; rowNum < 65536; rowNum++) {
Row row = sheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 10; cellNum++) {
Cell cell = row.createCell(cellNum);
cell.setCellValue(cellNum);
}
}
FileOutputStream fileOutputStream = new FileOutputStream(path + "页面访问数据表.xlsx");
workbook.write(fileOutputStream);
// 关闭流
fileOutputStream.close();
// 清除临时文件
((SXSSFWorkbook) workbook).dispose();
workbook.close();
}
Excel读操作
有这样一张表,我们来读取它并按照不同的类型进行处理和输出
public static void excelRead() throws Exception{
String path = "/Users/admin/Desktop/list/";
FileInputStream fileInputStream = new FileInputStream(path + "页面访问统计表.xls");
Workbook workbook = new HSSFWorkbook(fileInputStream);
Sheet sheet = workbook.getSheetAt(0);
//拿到表头行
Row row0 = sheet.getRow(0);
if(row0 != null) {
int cellCount = row0.getPhysicalNumberOfCells();
for (int cellNum = 0;cellNum < cellCount; cellNum++){
Cell cell = row0.getCell(cellNum);
if (cell != null){
String cellValue = cell.getStringCellValue();
System.out.print(cellValue + " | ");
}
}
System.out.println();
}
int rowCount = sheet.getPhysicalNumberOfRows();
for (int rowNum = 1;rowNum < rowCount;rowNum ++){
Row row = sheet.getRow(rowNum);
if (row != null){
int cellCount = row.getPhysicalNumberOfCells();
for (int cellNum = 0;cellNum < cellCount;cellNum ++){
Cell cell = row.getCell(cellNum);
if (cell != null){
CellType cellType = cell.getCellTypeEnum();
String cellValue = "";
switch (cellType){
case STRING:
System.out.print("【STRING】");
cellValue = cell.getStringCellValue();
break;
case BOOLEAN:
System.out.print("【BOOLEAN】");
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case BLANK:
System.out.print("【BLANK】");
cellValue = cell.getStringCellValue();
break;
case NUMERIC:
//要判断是普通的数字还是日期
System.out.print("【NUMERIC】");
if (DateUtil.isCellDateFormatted(cell)){
//是日期
System.out.print("【DATE】");
Date date = cell.getDateCellValue();
}else {
//不是日期
cellValue = new BigDecimal(cell.getNumericCellValue()).toPlainString();
}
break;
case FORMULA:
//是公式
System.out.print("【FORMULA】");
cellValue = cell.getCellFormula();
case ERROR:
cellValue = "ERROR";
break;
default:
cellValue = "UNKNOW";
break;
}
System.out.print(cellValue);
if(cellNum != cellCount-1){
System.out.print(" | ");
}
}
}
System.out.println();
}
}
fileInputStream.close();
workbook.close();
}
输出结果是这样的: