|
J2ee核心 | Java | 3404 次查看 |
|---|---|---|
本文将阐述如何用POI来读取/写入完整的Excel文件。 约定:POI项目2.0版现在已经接近正式发行阶段,开发进度迅速,不断有新的功能集成到原有的系统,同时也有对原有系统的修改。 为了保证本文的及时性,本文将按照最近的1.9开发版说明。虽然编译最近的发行版源代码也能正常运行,但现在的代码和2.0的发行版会有一些出入。 一、Excel基础 Microsoft Excel 97文件格式也被称为BIFF8,最近版本的Excel只对该格式作了少量的改动。增加对新格式的支持除了增加项目的复杂性之外,唯一的效果也许只是不得不使每个用户升级代码,没有什么实际的好处。 因此,在下文说明中,凡是提到Excel 97格式的地方其实都是指Excel从97到XP的格式。 二、HSSF概况 POI项目实现的Excel 97文件格式称为HSSF??也许你已经猜到,HSSF是Horrible SpreadSheet Format的缩写,也即“讨厌的电子表格格式”(微软使某些原本简单的事情过分复杂,同时又过分简单地处理了某些原本需要灵活性的事情,让人不胜佩服!) 也许HSSF的名字有点滑稽,就本质而言它是一个非常严肃、正规的API。通过HSSF,你可以用纯Java代码来读取、写入、修改Excel文件。 前面一篇文章提到了POIFS,那么HSSF和POIFS又有什么关系呢?就象其他POI的API一样,HSSF建立在POIFS的基础上,因此在HSSF内的有些代码和前文的某些代码很相似。不过,当我们编写基于HSSF API的代码时,一般不需要了解POIFS API的细节。 HSSF为读取操作提供了两类API:usermodel和eventusermodel,即“用户模型”和“事件-用户模型”。前者很好理解,后者比较抽象,但操作效率要高得多。usermodel主要有org.apache.poi.hssf.usermodel和org.apache.poi.hssf.eventusermodel包实现(在HSSF的早期版本中,org.apache.poi.hssf.eventusermodel属于eventmodel包)。 usermodel包把Excel文件映射成我们熟悉的结构,诸如Workbook、Sheet、Row、Cell等,它把整个结构以一组对象的形式保存在内存之中。eventusermodel要求用户熟悉文件格式的底层结构,它的操作风格类似于XML的SAX API和AWT的事件模型(这就是eventusermodel名称的起源),要掌握窍门才能用好。 另外,eventusermodel的API只提供读取文件的功能,也就是说不能用这个API来修改文件。 三、通过usermodel读取文件 用HSSF的usermodel读取文件很简单。首先创建一个InputStream,然后创建一个HSSFWorkbook: InputStream myxls = new FileInputStream("workbook.xls")); HSSFWorkbook wb = new HSSFWorkbook(myxls); 有了HSSFWorkbook实例,接下来就可以提取工作表、工作表的行和列,例如: HSSFSheet sheet = wb.getSheetAt(0); // 第一个工作表 HSSFRow row = sheet.getRow(2); // 第三行 HSSFCell cell = row.getCell((short)3); // 第四个单元格 上面这段代码提取出第一个工作表第三行第四单元格。利用单元格对象可以获得它的值,提取单元格的值时请注意它的类型: if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) { ("单元格是字符串,值是: " + cell.getStringCellValue()); } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { ("单元格是数字,值是: " + cell.getCellValue()); } else () { ("单元格的值不是字符串或数值。"); } 如果搞错了数据类型,程序将遇到异常。特别地,用HSSF处理日期数据要小心。Excel内部以数值的形式保存日期数据,区别日期数据的唯一办法是通过单元格的格式(如果你曾经在Excel中设置过日期格式,应该明白这是什么意思)。 因此,对于包含日期数据的单元格,cell.getCellType()将返回HSSFCell.CELL_TYPE_NUMERIC,不过利用工具函数HSSFDateUtil.isCellDateFormatted(cell)可以判断出单元格的值是否为日期。isCellDateFormatted函数通过比较单元格的日期和Excel的内置日期格式得出结论??可以想象,按照这种判断方法,很多时候isCellDateFormatted函数会返回否定的结论,存在一定的误判可能。 本文附录包含了一个在Servlet环境中利用HSSF创建和返回Excel工作簿的实例。 四、通过usermodel写入文件 写入XLS文件比读取XLS文件还要简单。创建一个HSSFWorkbook实例,然后在适当的时候创建一个把文件写入磁盘的OutputStream,但延迟到处理结束时创建OutputStream也可以: HSSFWorkbook wb = new HSSFWorkbook(); FileOutputStream fileOut = new FileOutputStream("workbook.xls"); wb.write(fileOut); fileOut.close(); 创建工作表及其内容必须从相应的父对象出发,例如: HSSFSheet sheet = wb.createSheet(); HSSFRow row = sheet.createRow((short)0); HSSFCell cell = row.createCell((short)0); cell.setCellValue(1); row.createCell((short)1).setCellValue(1.2); row.createCell((short)2).setCellValue("一个字符串"); row.createCell((short)3).setCellValue(true); 如果要设置单元格的样式,首先要创建一个样式对象,然后把它指定给一个单元格??或者把它指定给多个具有相同样式的单元格,例如,如果Excel表格中有一个摘要行,摘要行的数据必须是粗体、斜体,你可以创建一个summaryRowStyle样式对象,然后把这个样式指定给所有摘要行上的单元格。 注意,CellFormat和CellStyle对象是工作簿对象的成员,单元格对象只是引用它们。 ... HSSFCellStyle style = workbook.createCellStyle(); style.setDataFormat (HSSFDataFormat.getBuiltinFormat("($#,##0_);[Red]($#,##0)")); style.setFillBackgroundColor(HSSFColor.AQUA.index); style.setFillPattern(HSSFCellStyle.BIG_SPOTS); ... someCell.setCellStyle(style); someOtherCell.setCellStyle(style); 版本较新的HSSF允许使用数量有限的Excel公式。这一功能目前还是“Beta级质量”,正式使用之前务必仔细测试。指定公式的方式类如:someCell.setCellFormula(SUM(A1:A2:);。 当前,公式中已经可以调用所有内建的函数或操作符,但逻辑操作符和函数(例如IF函数)除外,这部分功能目前还在开发之中。 |
||