POI使用总结
1.POI读取Excel
打开工作簿的方式有以下两种简单的应用,POI读取和输出工作簿文件都可以通过以下两种方式来声明:
//通过输入流的方式打开本地磁盘上的文件 Workbook wb = WorkbookFactory.create(new FileInputStream("D:/测试.xls")); //通过文件的方式打开本地磁盘上的文件 Workbook wbf = WorkbookFactory.create(new File("D:/测试.xls")); |
以上两种方式主要是将文件读取到了对象当中,如果需要对操作后的对象进行输出,则可以通过如下方式:
//将生成好的工作簿对象通过流的方式输出到本地磁盘中 FileOutputStream fos = new FileOutputStream("D:/测试生成.xls"); wb.write(fos); fos.close(); |
工作簿由几个sheet页组成,然后下边我们就开始进行获取sheet页的操作:
//通过sheet名字的方式获取 Sheet sheetByName = wb.getSheet("测试"); //通过sheet位置的方式获取 Sheet sheetByIndex = wb.getSheetAt(0); |
注意的是:sheet页中的位置下标从0开始,所以如果获取第0个位置的sheet页时,默认就是第一个sheet页。
一个sheet页由行组成,一行又由许多单元格组成,这正符合java面向对象的思想:
//获取第一行 Row row = sheetByIndex.getRow(0); //获取第一行第一个单元格 Cell cell = row.getCell(0); |
这样一个工作表就被我们解析完了,就可以拿到我们想要的一个一个的对象,然后就可以对这些对象当中的属性和方法开始进行剖析了。
因为现在旨在讲解读取,那就先写出一些常用的读取Excel的方法:
//获取sheet页的第一行数据的位置 int firstRowNum = sheetByIndex.getFirstRowNum(); //获取sheet页的最后一行数据的位置 int lastRowNum = sheetByIndex.getLastRowNum(); //获取当前行第一列数据位置 int firstColNum = row.getFirstCellNum(); //获取当前行最后一列数据位置 int lastColNum = row.getLastCellNum();
//获取当前的行号 int currentRow = row.getRowNum(); //获取行高 int rowHieght = row.getHeight();
//获取布尔类型的单元格的值 cell.getBooleanCellValue(); //获取单元格中的公式 cell.getCellFormula(); //获取日期类型的单元格的值 cell.getDateCellValue(); //获取数值类型的单元格的值 cell.getNumericCellValue(); //获取单元格的样式 cell.getCellStyle(); //获取当前单元格中值的类型 cell.getCellType(); //获取当前单元格所在列 cell.getColumnIndex(); |
这里需要注意的是:
lastColNum 和 lastRowNum获取出来的数值结果会跟我们想象的有些差别,比如说一个文档中有6行5列,lastColNum为5,lastRowNum为5。希望大家如果以后对Excel操作,如果用到最后一列的获取时要谨慎使用。
如果在使用获取单元格中值的方法,需要提前确定好单元格中的类型,否则就会造成程序出错,可以这样来解决:
/** * 获取单元格的值,因为poi获取单元格数据需要匹配单元格格式 * @param cell 单元格对象 * @return */ private String getCellValue(Cell cell) { String contents = null; switch (cell.getCellType()) { case Cell.CELL_TYPE_BLANK://判断是否空值 contents = ""; break; case Cell.CELL_TYPE_BOOLEAN://判断是否是布尔类型的值 contents = String.valueOf(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_FORMULA://判断是否是公式类型 contents = String.valueOf(cell.getCellFormula()); break; case Cell.CELL_TYPE_NUMERIC://判断是否是数字,因为日期精确不是yyyy-MM-dd就会自动取数字,所以做以下判断 //判断单元格是不是日期类型,yyyy-MM-dd HH:mm:ss 会转换为例:Mon Nov 28 15:00:00 CST 2011形式 if (HSSFDateUtil.isCellDateFormatted(cell)) { contents = cell.getDateCellValue().toString(); } else { contents = String.valueOf(cell.getNumericCellValue()); } break; case Cell.CELL_TYPE_STRING: contents = cell.getStringCellValue(); break; default: contents = null; break; } return contents; } |
这样读取就到此告一段落了。
2.POI导出Excel
POI在创建工作表、行、列的时候和读取Excel是一样的:
//创建Sheet工作表 Sheet sheet = wb.createSheet("格式测试POI"); //创建一行 row = sheet.createRow(0); //设置行高 row.setHeight((short) 420); //创建一个单元格 cell = row.createCell(0); //将单元格内容设为"格式测试" cell.setCellValue("格式测试"); //设置单元格样式 cell.setCellStyle(titleStyle); |
POI导出Excel可以选择两种方式:
- 通过模板的导出:
通过模板导出主要就是在项目中,或本地磁盘中有此模板,单元格的样式和其中的单元格和并出来的区域,斜线表头等等,都先设置好,然后在程序需要输出的时候拿到模板文件,直接在其中写入要写的数据,将样式填充好,这个方法还是很简单的,下边主要着重讲解如何控制代码进行导出。
- 通过自己控制代码,控制样式的导出:
POI所有样式的超类为CellStyle,所以所有的样式都包含在了CellStyle中,在操作导出样式的时候直接在CellStyle中进行操作就可以了。
//创建单元格样式 CellStyle cellStyle = wb.createCellStyle(); //创建字体 Font cellFont = wb.createFont(); //设置字体倾斜 cellFont.setItalic(true); //设置字体加粗 cellFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); //设置字体高度 cellFont.setFontHeight((short) 220); //设置字体 cellFont.setFontName("黑体"); //设置删除线 cellFont.setStrikeout(true); //设置下划线 cellFont.setUnderline(Font.U_DOUBLE); //设置文字水平居中 cellStyle.setAlignment(CellStyle.ALIGN_CENTER); //设置下边框 cellStyle.setBorderBottom((short) BorderStyle.DASH_DOT.ordinal()); //设置左边框 cellStyle.setBorderLeft(CellStyle.BORDER_DASHED); //设置右边框 cellStyle.setBorderRight((short) BorderStyle.DOUBLE.ordinal()); //设置上边框 cellStyle.setBorderTop(CellStyle.BORDER_MEDIUM); //设置填充样式,如果设置前景色填充,则必须要有此项 cellStyle.setFillPattern((short) FillPatternType.BIG_SPOTS.ordinal()); //设置前景色 cellStyle.setFillForegroundColor(HSSFColor.RED.index); //设置字体 cellStyle.setFont(cellFont); //设置自动换行,默认为不换行 cellStyle.setWrapText(true); //设置右边框颜色 cellStyle.setRightBorderColor(HSSFColor.RED.index); //设置文本旋转度 cellStyle.setRotation((short) 30); //设置缩进 cellStyle.setIndention((short) 20); //设置垂直对齐方式 cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); |
根据以上的代码就可以做出一个样式出来。
合并单元格,合并单元格也有两种方式:
//合并A1:G1区域的单元格 CellRangeAddress cellrangeaddress = CellRangeAddress.valueOf("A1:G1"); //合并A1:G1区域的单元格 CellRangeAddress cellrangeaddress = new CellRangeAddress(0, 0, 0, 6); |
以上两种方式都是对A1:G1区域的单元格进行合并,第一种方式更加形象和具体,也更接近于操作Excel的习惯;第二种方式需要自己去琢磨单元格区域的位置,所以我更倾向于第一种的操作。
在合并的单元格中添加数据的方法,只需要在合并单元格的第一个单元格的位置加入数据即可,如果需要设定样式,也只需要对第一个进行操作,但是如果对于给合并单元格设置边框则需要用到另一种方式,需要用到POI当中的另一个工具类RegionUtil。
/** * 为合并以后的单元格加上边框 * @param cellrangeaddress 合并单元格区域 * @param sheet 工作表 * @param workbook 工作簿空间 */ public void addRegionBorder(CellRangeAddress cellrangeaddress, Sheet sheet, Workbook workbook) { RegionUtil.setBorderBottom(HSSFCellStyle.BORDER_THIN, cellrangeaddress, sheet, workbook); RegionUtil.setBorderLeft(HSSFCellStyle.BORDER_THIN, cellrangeaddress, sheet, workbook); RegionUtil.setBorderRight(HSSFCellStyle.BORDER_THIN, cellrangeaddress, sheet, workbook); RegionUtil.setBorderTop(HSSFCellStyle.BORDER_THIN, cellrangeaddress, sheet, workbook); } |
合并单元格之所以要这样做,主要是因为如果只用一个单元格的样式来设置此合并区域单元格的样式的话就会出现缺少边框的现象。
POI还可以对Excel表格进行冻结和对所选单元格进行自动筛选的功能,实现代码如下:
//冻结单元格,冻结区域为1、2行 sheet.createFreezePane(0, 2); //设置自动筛选为A2:E2的区域 cellrangeaddress = CellRangeAddress.valueOf("C2:G2"); //将所设置的区域设置为自动筛选 sheet.setAutoFilter(cellrangeaddress); |
这样一个Excel的格式基本就设置完成了,现在可以将文件进行输出了:
//打开输出流到D:/POI.xls文件 FileOutputStream fos = new FileOutputStream("D:/POI.xls"); //将文件写入到输出流中 wb.write(fos); if (fos != null) { //关闭输出流 fos.close(); } |
如果需要改为下载方式,就可以用获得的输出流,然后将文件输出到响应的输出流中了。