Apache的POI组件是Java操作Microsoft Office办公套件的强大API,其中对Word,Excel和PowperPoint都有支持,当然使用较多的还是Excel,因为Word和PowerPoint用程序动态操作的应用较少。那么本文就结合POI来介绍一下操作Excel的方法。 
    Office 2007的文件结构完全不同于2003,所以对于两个版本的Office组件,POI有不同的处理API,分开使用即可。首先来说几个Excel的基本概念。对于一个Excel文件,这称为一个工作簿(Workbook),打开Excel之后,在下方会有sheet1/2/3这样的选项卡,点击可以切换到不同的sheet中,这个sheet称作工作表。每个工作表就是我们编辑的区域,这是一张二维表,阿拉伯数字控制行数,从1开始,而程序中还是0,类似数组和集合。字母控制列数,从A开始,Z以后是两个字母控制。对于每一行,我们称为Row,列就是Column,行列可以确定唯一的一个元素,那么就是单元格,称为Cell。 
    POI组件可以方便的操纵这些元素,但初次接触POI可能会有畏惧心理,因为要对每个单元格进行设置,那么不管是用数组还是集合,从工作簿,工作表,行下来的代码量都不会小,这是不能避免的,但是按照这个处理顺序走,就一定可以得到结果。 
    有了这些基础的概念之后,我们就可以操作Excel了。先来看一下所需的依赖,因为涉及到2007,就要额外加一些依赖。 
 
    下面从读取Excel开始,首先建立一个Excel 2003以下版本的xls文件。设定几列来看。来存储学生信息的Excel表如下: 
 
    这里的姓名,性别和班级是文本值,而年龄和成绩是数字值,这在设计对象和处理时要注意区分。那么可以如下设计这个对象:

  1. package org.ourpioneer.excel.bean;
  2. /**
  3. * 学生信息
  4. *
  5. * @author Nanlei
  6. *
  7. */
  8. public class Student {
  9. private String name;
  10. private String gender;
  11. private int age;
  12. private String sclass;
  13. private int score;
  14. public Student() {
  15. super();
  16. }
  17. public Student(String name, String gender, int age, String sclass, int score) {
  18. super();
  19. this.name = name;
  20. this.gender = gender;
  21. this.age = age;
  22. this.sclass = sclass;
  23. this.score = score;
  24. }
  25. //省略了getter和setter方法
  26. @Override
  27. public String toString() {
  28. return "Student [age=" + age + ", gender=" + gender + ", name=" + name
  29. + ", sclass=" + sclass + ", score=" + score + "]";
  30. }
  31. }

提供一个有参数的构造方法,用于生成对象写入Excel文档。这个对象就能刻画Excel文件中的数据了,下面就是写程序将Excel文件加载并处理,然后将内容读出,读取顺序是工作簿->工作表->行->单元格。这样一分析就很简单了。我们定义两个Excel文件,内容相同,只是版本不同,分2003和2007来处理。 
    创建工作簿时可以接收一个输入流对象,那么输入流对象可以从文件对象来生成,这样就可以继续进行了。取出工作表,取出行,遍历单元格,数据就拿到了。代码如下:

  1. package org.ourpioneer.excel;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import org.apache.poi.hssf.usermodel.HSSFCell;
  9. import org.apache.poi.hssf.usermodel.HSSFRow;
  10. import org.apache.poi.hssf.usermodel.HSSFSheet;
  11. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  12. import org.ourpioneer.excel.bean.Student;
  13. /**
  14. * POI读取Excel示例,分2003和2007
  15. *
  16. * @author Nanlei
  17. *
  18. */
  19. public class ReadExcel {
  20. private static String xls2003 = "C:\\student.xls";
  21. private static String xlsx2007 = "C:\\student.xlsx";
  22. /**
  23. * 读取Excel2003的示例方法
  24. *
  25. * @param filePath
  26. * @return
  27. */
  28. private static List<Student> readFromXLS2003(String filePath) {
  29. File excelFile = null;// Excel文件对象
  30. InputStream is = null;// 输入流对象
  31. String cellStr = null;// 单元格,最终按字符串处理
  32. List<Student> studentList = new ArrayList<Student>();// 返回封装数据的List
  33. Student student = null;// 每一个学生信息对象
  34. try {
  35. excelFile = new File(filePath);
  36. is = new FileInputStream(excelFile);// 获取文件输入流
  37. HSSFWorkbook workbook2003 = new HSSFWorkbook(is);// 创建Excel2003文件对象
  38. HSSFSheet sheet = workbook2003.getSheetAt(0);// 取出第一个工作表,索引是0
  39. // 开始循环遍历行,表头不处理,从1开始
  40. for (int i = 1; i <= sheet.getLastRowNum(); i++) {
  41. student = new Student();// 实例化Student对象
  42. HSSFRow row = sheet.getRow(i);// 获取行对象
  43. if (row == null) {// 如果为空,不处理
  44. continue;
  45. }
  46. // 循环遍历单元格
  47. for (int j = 0; j < row.getLastCellNum(); j++) {
  48. HSSFCell cell = row.getCell(j);// 获取单元格对象
  49. if (cell == null) {// 单元格为空设置cellStr为空串
  50. cellStr = "";
  51. } else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {// 对布尔值的处理
  52. cellStr = String.valueOf(cell.getBooleanCellValue());
  53. } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {// 对数字值的处理
  54. cellStr = cell.getNumericCellValue() + "";
  55. } else {// 其余按照字符串处理
  56. cellStr = cell.getStringCellValue();
  57. }
  58. // 下面按照数据出现位置封装到bean中
  59. if (j == 0) {
  60. student.setName(cellStr);
  61. } else if (j == 1) {
  62. student.setGender(cellStr);
  63. } else if (j == 2) {
  64. student.setAge(new Double(cellStr).intValue());
  65. } else if (j == 3) {
  66. student.setSclass(cellStr);
  67. } else {
  68. student.setScore(new Double(cellStr).intValue());
  69. }
  70. }
  71. studentList.add(student);// 数据装入List
  72. }
  73. } catch (IOException e) {
  74. e.printStackTrace();
  75. } finally {// 关闭文件流
  76. if (is != null) {
  77. try {
  78. is.close();
  79. } catch (IOException e) {
  80. e.printStackTrace();
  81. }
  82. }
  83. }
  84. return studentList;
  85. }
  86. /**
  87. * 主函数
  88. *
  89. * @param args
  90. */
  91. public static void main(String[] args) {
  92. long start = System.currentTimeMillis();
  93. List<Student> list = readFromXLS2003(xls2003);
  94. for (Student student : list) {
  95. System.out.println(student);
  96. }
  97. long end = System.currentTimeMillis();
  98. System.out.println((end - start) + " ms done!");
  99. }
  100. }

做几点说明,如果不处理表头,那么就从准备处理的行开始,而整个sheet对行的索引是从0开始的,而Excel中是1,这点和数组/集合类似。对于单元格中的数字,默认按double类型处理,所以只能字符串转double,再取出int值。最后执行主函数,得到如下内容: 
 
    这样就拿到对象的List了,之后要持久到数据库或者直接做业务逻辑就随心所欲了。下面来看2007的处理,处理流程和2003是类似的,区别就是使用的对象,2003中对象是HSSF*格式的,而2007是XSSF*格式的。方法如下:

  1. public static List<Student> readFromXLSX2007(String filePath) {
  2. File excelFile = null;// Excel文件对象
  3. InputStream is = null;// 输入流对象
  4. String cellStr = null;// 单元格,最终按字符串处理
  5. List<Student> studentList = new ArrayList<Student>();// 返回封装数据的List
  6. Student student = null;// 每一个学生信息对象
  7. try {
  8. excelFile = new File(filePath);
  9. is = new FileInputStream(excelFile);// 获取文件输入流
  10. XSSFWorkbook workbook2007 = new XSSFWorkbook(is);// 创建Excel2003文件对象
  11. XSSFSheet sheet = workbook2007.getSheetAt(0);// 取出第一个工作表,索引是0
  12. // 开始循环遍历行,表头不处理,从1开始
  13. for (int i = 1; i <= sheet.getLastRowNum(); i++) {
  14. student = new Student();// 实例化Student对象
  15. XSSFRow row = sheet.getRow(i);// 获取行对象
  16. if (row == null) {// 如果为空,不处理
  17. continue;
  18. }
  19. // 循环遍历单元格
  20. for (int j = 0; j < row.getLastCellNum(); j++) {
  21. XSSFCell cell = row.getCell(j);// 获取单元格对象
  22. if (cell == null) {// 单元格为空设置cellStr为空串
  23. cellStr = "";
  24. } else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {// 对布尔值的处理
  25. cellStr = String.valueOf(cell.getBooleanCellValue());
  26. } else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {// 对数字值的处理
  27. cellStr = cell.getNumericCellValue() + "";
  28. } else {// 其余按照字符串处理
  29. cellStr = cell.getStringCellValue();
  30. }
  31. // 下面按照数据出现位置封装到bean中
  32. if (j == 0) {
  33. student.setName(cellStr);
  34. } else if (j == 1) {
  35. student.setGender(cellStr);
  36. } else if (j == 2) {
  37. student.setAge(new Double(cellStr).intValue());
  38. } else if (j == 3) {
  39. student.setSclass(cellStr);
  40. } else {
  41. student.setScore(new Double(cellStr).intValue());
  42. }
  43. }
  44. studentList.add(student);// 数据装入List
  45. }
  46. } catch (IOException e) {
  47. e.printStackTrace();
  48. } finally {// 关闭文件流
  49. if (is != null) {
  50. try {
  51. is.close();
  52. } catch (IOException e) {
  53. e.printStackTrace();
  54. }
  55. }
  56. }
  57. return studentList;
  58. }

再次运行主函数,我们得到如下输出: 
 
    可以看出,对2007的处理时间明显增长,还是2003版本效率更好,不过在使用Office组件时2007更便捷,而处理2003的程序效率更好。如何使用二者?根据程序业务来综合决定,看看牺牲掉哪部分。 
    下面来做简单的文件写入,也就是准备输入写入Excel文件,为了演示,直接创建对象,而实际应用中数据可以是来自数据库的。写入文件就是文件解析的逆过程。但POI的组件不是从单元格开始创建文件的,还是从工作簿开始创建,进而创建工作表,行和单元格,最终将整个工作簿写入文件,完成操作。我们来看具体写法。

  1. package org.ourpioneer.excel;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.List;
  7. import org.apache.poi.hssf.usermodel.HSSFCell;
  8. import org.apache.poi.hssf.usermodel.HSSFRow;
  9. import org.apache.poi.hssf.usermodel.HSSFSheet;
  10. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  11. import org.ourpioneer.excel.bean.Student;
  12. /**
  13. * 生成Excel示例,2003和2007
  14. *
  15. * @author Nanlei
  16. *
  17. */
  18. public class GenerateExcel {
  19. private static String xls2003 = "C:\\student.xls";
  20. private static String xlsx2007 = "C:\\student.xlsx";
  21. private static List<Student> studentList = null;
  22. private static Student[] students = new Student[4];
  23. /**
  24. * 静态块初始化数据
  25. */
  26. static {
  27. studentList = new ArrayList<Student>();
  28. students[0] = new Student("张三", "男", 23, "一班", 94);
  29. students[1] = new Student("李四", "女", 20, "一班", 92);
  30. students[2] = new Student("王五", "男", 21, "一班", 87);
  31. students[3] = new Student("赵六", "女", 22, "一班", 83);
  32. studentList.addAll(Arrays.asList(students));
  33. }
  34. /**
  35. * 创建2003文件的方法
  36. *
  37. * @param filePath
  38. */
  39. public static void generateExcel2003(String filePath) {
  40. // 先创建工作簿对象
  41. HSSFWorkbook workbook2003 = new HSSFWorkbook();
  42. // 创建工作表对象并命名
  43. HSSFSheet sheet = workbook2003.createSheet("学生信息统计表");
  44. // 遍历集合对象创建行和单元格
  45. for (int i = 0; i < studentList.size(); i++) {
  46. // 取出Student对象
  47. Student student = studentList.get(i);
  48. // 创建行
  49. HSSFRow row = sheet.createRow(i);
  50. // 开始创建单元格并赋值
  51. HSSFCell nameCell = row.createCell(0);
  52. nameCell.setCellValue(student.getName());
  53. HSSFCell genderCell = row.createCell(1);
  54. genderCell.setCellValue(student.getGender());
  55. HSSFCell ageCell = row.createCell(2);
  56. ageCell.setCellValue(student.getAge());
  57. HSSFCell sclassCell = row.createCell(3);
  58. sclassCell.setCellValue(student.getSclass());
  59. HSSFCell scoreCell = row.createCell(4);
  60. scoreCell.setCellValue(student.getScore());
  61. }
  62. // 生成文件
  63. File file = new File(filePath);
  64. FileOutputStream fos = null;
  65. try {
  66. fos = new FileOutputStream(file);
  67. workbook2003.write(fos);
  68. } catch (Exception e) {
  69. e.printStackTrace();
  70. } finally {
  71. if (fos != null) {
  72. try {
  73. fos.close();
  74. } catch (Exception e) {
  75. e.printStackTrace();
  76. }
  77. }
  78. }
  79. }
  80. /**
  81. * 主函数
  82. *
  83. * @param args
  84. */
  85. public static void main(String[] args) {
  86. long start = System.currentTimeMillis();
  87. generateExcel2003(xls2003);
  88. long end = System.currentTimeMillis();
  89. System.out.println((end - start) + " ms done!");
  90. }
  91. }

这样就生成了2003版Excel文件,只是最简单的操作,并没有涉及到单元格格式等操作,而2007的方法就是改改对象的名称,很简单,这里不再贴出了。

Apache POI组件操作Excel,制作报表(一)的更多相关文章

  1. Apache POI组件操作Excel,制作报表(四)

    Apache POI组件操作Excel,制作报表(四) 博客分类: 探索实践 ExcelApacheSpringMVCServlet      上一篇我们介绍了如何制作复杂报表的分析和设计,本篇结合S ...

  2. Apache POI组件操作Excel,制作报表(三)

    Apache POI组件操作Excel,制作报表(三) 博客分类: 探索实践 ExcelApache算法Office单元测试      上一篇介绍了POI组件操作Excel时如何对单元格和行进行设置, ...

  3. Apache POI组件操作Excel,制作报表(二)

    本文接上一篇继续探究POI组件的使用.     现在来看看Excel的基本设置问题,以2007为例,先从工作簿来说,设置列宽,因为生成表格列应该固定,而行是遍历生成的,所以可以在工作簿级别来设置列宽, ...

  4. java用org.apache.poi包操作excel

    一.POI简介 Jakarta POI 是apache的子项目,目标是处理ole2对象.它提供了一组操纵Windows文档的Java API 目前比较成熟的是HSSF接口,处理MS Excel(97- ...

  5. C#操作Excel开发报表系列整理(转)

    C#操作Excel进行报表开发系列共写了七篇,也已经有很久没有新东西了,现在整理一下,方便以后查阅,如果有写新的,会同时更新.需要注意的是因为Office的版本不同,实际的代码可能会有所不同,但是都是 ...

  6. C#操作Excel开发报表系列整理

    C#操作Excel进行报表开发系列共写了八篇,也已经有很久没有新东西了,现在整理一下,方便以后查阅,如果有写新的,会同时更新.需要注意的是因为Office的版本不同,实际的代码可能会有所不同,但是都是 ...

  7. 使用JXL组件操作Excel和导出文件

    这段时间参与的项目要求做几张Excel报表,由于项目框架使用了jxl组件,所以把jxl组件的详细用法归纳总结一下.本文主要讲述了以下内容: JXL及相关工具简介 如何安装JXL JXL的基本操作 创建 ...

  8. 导入org.apache.poi.xssf 读取excel

    POI 操作 excel  用XSSF 方式时,如果不能自动导入 org.apache.poi.xssf 对应jar 包,则可以Apache 官网进行下载,自行导入. step1: 访问 http:/ ...

  9. Apache POI 实现对 Excel 文件读写

    1. Apache POI 简介 Apache POI是Apache软件基金会的开放源码函式库. 提供API给Java应用程序对Microsoft Office格式档案读和写的功能. 老外起名字总是很 ...

随机推荐

  1. (转载)XML Tutorial for iOS: How To Read and Write XML Documents with GDataXML

    In my recent post on How To Choose the Best XML Parser for Your iPhone Project, Saliom from the comm ...

  2. 使用Win32::OLE操作Excel——Excel对象模型

    像VBA操作Excel一样,Win32::OLE模块也是通过对象操作来控制Excel. 如果想自动化操作和控制Excel应用程序,则必须要与Excel对象模型所提供的对象进行交互.理解和熟悉Excel ...

  3. asp net 编程问题 实现下一篇 和上一篇效果

    首先是access数据库,有一个名为news的表,里面有三个字段,分别为id,classid 和name 其中id为主键,classid可以重复 现在有以下数据: id classid name 1 ...

  4. 从blob字段读取图片 在浏览器显示

    public byte[] GetProImg(string JID) { byte[] Buffer = null; using (OracleConnection conn = new Oracl ...

  5. redis批量执行

    1.首先把redis命令放在txt文件中 eg: 文件名:  test.txt 内容如下: HMSET HM_001 name zhang01 age HMSET HM_002 name zhang0 ...

  6. hbase 单机模式安装

    1:下载安装包(我下载的0.94版本,如果考虑后期与hadoop兼容,需要找合适的版本) http://mirrors.hust.edu.cn/apache/hbase/hbase-0.94.20/h ...

  7. 给软件增加注册功能 c#

    1.软件注册类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...

  8. C# ITextSharp pdf 自动打印

    PDF生成后直接进入打印预览不用下载 using iTextSharp.text; using iTextSharp.text.pdf; Document pdfDoc = new Document( ...

  9. 三个重要的游标sp_cursoropen

    請問這三個存諸過程的作用是什么﹖ sp_cursoropen, sp_cursorfetch, sp_cursorclose API 服务器游标实现  SQL Server OLE DB 提供程序. ...

  10. JAVA语言对比C++语言的几个优点和自身的关键特性

    之所以写这篇博客不是为了比较JAVA语言和C++语言到底孰优孰劣,而是从语言本身出发进行对比总结程序编码设计上的差别.因水平有限,某些内容可能太过片面,欢迎指正和讨论. JAVA语言在设计上很好地借鉴 ...