Apache POI組件操作Excel,製作報表(一)

來源:互聯網
上載者:User

 

    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表如下: 

 

這裡的姓名,性別和班級是文本值,而年齡和成績是數字值,這在設計對象和處理時要注意區分。那麼可以如下設計這個對象: 

package org.ourpioneer.excel.bean;/** * 學生資訊 *  * @author Nanlei *  */public class Student {private String name;private String gender;private int age;private String sclass;private int score;public Student() {super();}public Student(String name, String gender, int age, String sclass, int score) {super();this.name = name;this.gender = gender;this.age = age;this.sclass = sclass;this.score = score;}//省略了getter和setter方法@Overridepublic String toString() {return "Student [age=" + age + ", gender=" + gender + ", name=" + name+ ", sclass=" + sclass + ", score=" + score + "]";}}

提供一個有參數的構造方法,用於產生對象寫入Excel文檔。這個對象就能刻畫Excel檔案中的資料了,下面就是寫程式將Excel檔案載入並處理,然後將內容讀出,讀取順序是活頁簿->工作表->行->儲存格。這樣一分析就很簡單了。我們定義兩個Excel檔案,內容相同,只是版本不同,分2003和2007來處理。 
    建立活頁簿時可以接收一個輸入資料流對象,那麼輸入資料流對象可以從檔案對象來產生,這樣就可以繼續進行了。取出工作表,取出行,遍曆儲存格,資料就拿到了。代碼如下: 

package org.ourpioneer.excel;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.List;import org.apache.poi.hssf.usermodel.HSSFCell;import org.apache.poi.hssf.usermodel.HSSFRow;import org.apache.poi.hssf.usermodel.HSSFSheet;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.ourpioneer.excel.bean.Student;/** * POI讀取Excel樣本,分2003和2007 *  * @author Nanlei *  */public class ReadExcel {private static String xls2003 = "C:\\student.xls";private static String xlsx2007 = "C:\\student.xlsx";/** * 讀取Excel2003的樣本方法 *  * @param filePath * @return */private static List<Student> readFromXLS2003(String filePath) {File excelFile = null;// Excel檔案對象InputStream is = null;// 輸入資料流對象String cellStr = null;// 儲存格,最終按字串處理List<Student> studentList = new ArrayList<Student>();// 返回封裝資料的ListStudent student = null;// 每一個學生資訊對象try {excelFile = new File(filePath);is = new FileInputStream(excelFile);// 擷取檔案輸入資料流HSSFWorkbook workbook2003 = new HSSFWorkbook(is);// 建立Excel2003檔案對象HSSFSheet sheet = workbook2003.getSheetAt(0);// 取出第一個工作表,索引是0// 開始迴圈遍曆行,表頭不處理,從1開始for (int i = 1; i <= sheet.getLastRowNum(); i++) {student = new Student();// 執行個體化Student對象HSSFRow row = sheet.getRow(i);// 擷取行對象if (row == null) {// 如果為空白,不處理continue;}// 迴圈遍曆儲存格for (int j = 0; j < row.getLastCellNum(); j++) {HSSFCell cell = row.getCell(j);// 擷取儲存格對象if (cell == null) {// 儲存格為空白設定cellStr為空白串cellStr = "";} else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {// 對布爾值的處理cellStr = String.valueOf(cell.getBooleanCellValue());} else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {// 對數字值的處理cellStr = cell.getNumericCellValue() + "";} else {// 其餘按照字串處理cellStr = cell.getStringCellValue();}// 下面按照資料出現位置封裝到bean中if (j == 0) {student.setName(cellStr);} else if (j == 1) {student.setGender(cellStr);} else if (j == 2) {student.setAge(new Double(cellStr).intValue());} else if (j == 3) {student.setSclass(cellStr);} else {student.setScore(new Double(cellStr).intValue());}}studentList.add(student);// 資料裝入List}} catch (IOException e) {e.printStackTrace();} finally {// 關閉檔案流if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return studentList;}/** * 主函數 *  * @param args */public static void main(String[] args) {long start = System.currentTimeMillis();List<Student> list = readFromXLS2003(xls2003);for (Student student : list) {System.out.println(student);}long end = System.currentTimeMillis();System.out.println((end - start) + " ms done!");}}

做幾點說明,如果不處理表頭,那麼就從準備處理的行開始,而整個sheet對行的索引是從0開始的,而Excel中是1,這點和數組/集合類似。對於儲存格中的數字,預設按double類型處理,所以只能字串轉double,再取出int值。最後執行主函數,得到如下內容: 

這樣就拿到對象的List了,之後要持久到資料庫或者直接做商務邏輯就隨心所欲了。下面來看2007的處理,處理流程和2003是類似的,區別就是使用的對象,2003中對象是HSSF*格式的,而2007是XSSF*格式的。方法如下: 

public static List<Student> readFromXLSX2007(String filePath) {File excelFile = null;// Excel檔案對象InputStream is = null;// 輸入資料流對象String cellStr = null;// 儲存格,最終按字串處理List<Student> studentList = new ArrayList<Student>();// 返回封裝資料的ListStudent student = null;// 每一個學生資訊對象try {excelFile = new File(filePath);is = new FileInputStream(excelFile);// 擷取檔案輸入資料流XSSFWorkbook workbook2007 = new XSSFWorkbook(is);// 建立Excel2003檔案對象XSSFSheet sheet = workbook2007.getSheetAt(0);// 取出第一個工作表,索引是0// 開始迴圈遍曆行,表頭不處理,從1開始for (int i = 1; i <= sheet.getLastRowNum(); i++) {student = new Student();// 執行個體化Student對象XSSFRow row = sheet.getRow(i);// 擷取行對象if (row == null) {// 如果為空白,不處理continue;}// 迴圈遍曆儲存格for (int j = 0; j < row.getLastCellNum(); j++) {XSSFCell cell = row.getCell(j);// 擷取儲存格對象if (cell == null) {// 儲存格為空白設定cellStr為空白串cellStr = "";} else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {// 對布爾值的處理cellStr = String.valueOf(cell.getBooleanCellValue());} else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {// 對數字值的處理cellStr = cell.getNumericCellValue() + "";} else {// 其餘按照字串處理cellStr = cell.getStringCellValue();}// 下面按照資料出現位置封裝到bean中if (j == 0) {student.setName(cellStr);} else if (j == 1) {student.setGender(cellStr);} else if (j == 2) {student.setAge(new Double(cellStr).intValue());} else if (j == 3) {student.setSclass(cellStr);} else {student.setScore(new Double(cellStr).intValue());}}studentList.add(student);// 資料裝入List}} catch (IOException e) {e.printStackTrace();} finally {// 關閉檔案流if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return studentList;}

 

 再次運行主函數,我們得到如下輸出: 

可以看出,對2007的處理時間明顯增長,還是2003版本效率更好,不過在使用Office組件時2007更便捷,而處理2003的程式效率更好。如何使用二者?根據程式業務來綜合決定,看看犧牲掉哪部分。 
    下面來做簡單的檔案寫入,也就是準備輸入寫入Excel檔案,為了示範,直接建立對象,而實際應用中資料可以是來自資料庫的。寫入檔案就是檔案解析的逆過程。但POI的組件不是從儲存格開始建立檔案的,還是從活頁簿開始建立,進而建立工作表,行和儲存格,最終將整個活頁簿寫入檔案,完成操作。我們來看具體寫法。

package org.ourpioneer.excel;import java.io.File;import java.io.FileOutputStream;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import org.apache.poi.hssf.usermodel.HSSFCell;import org.apache.poi.hssf.usermodel.HSSFRow;import org.apache.poi.hssf.usermodel.HSSFSheet;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.ourpioneer.excel.bean.Student;/** * 產生Excel樣本,2003和2007 *  * @author Nanlei *  */public class GenerateExcel {private static String xls2003 = "C:\\student.xls";private static String xlsx2007 = "C:\\student.xlsx";private static List<Student> studentList = null;private static Student[] students = new Student[4];/** * 靜態塊初始化資料 */static {studentList = new ArrayList<Student>();students[0] = new Student("張三", "男", 23, "一班", 94);students[1] = new Student("李四", "女", 20, "一班", 92);students[2] = new Student("王五", "男", 21, "一班", 87);students[3] = new Student("趙六", "女", 22, "一班", 83);studentList.addAll(Arrays.asList(students));}/** * 建立2003檔案的方法 *  * @param filePath */public static void generateExcel2003(String filePath) {// 先建立活頁簿對象HSSFWorkbook workbook2003 = new HSSFWorkbook();// 建立工作表對象並命名HSSFSheet sheet = workbook2003.createSheet("學生資訊統計表");// 遍曆集合對象建立行和儲存格for (int i = 0; i < studentList.size(); i++) {// 取出Student對象Student student = studentList.get(i);// 建立行HSSFRow row = sheet.createRow(i);// 開始建立儲存格並賦值HSSFCell nameCell = row.createCell(0);nameCell.setCellValue(student.getName());HSSFCell genderCell = row.createCell(1);genderCell.setCellValue(student.getGender());HSSFCell ageCell = row.createCell(2);ageCell.setCellValue(student.getAge());HSSFCell sclassCell = row.createCell(3);sclassCell.setCellValue(student.getSclass());HSSFCell scoreCell = row.createCell(4);scoreCell.setCellValue(student.getScore());}// 組建檔案File file = new File(filePath);FileOutputStream fos = null;try {fos = new FileOutputStream(file);workbook2003.write(fos);} catch (Exception e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (Exception e) {e.printStackTrace();}}}}/** * 主函數 *  * @param args */public static void main(String[] args) {long start = System.currentTimeMillis();generateExcel2003(xls2003);long end = System.currentTimeMillis();System.out.println((end - start) + " ms done!");}}

 

  這樣就產生了2003版Excel檔案,只是最簡單的操作,並沒有涉及到儲存格格式等操作,而2007的方法就是改改對象的名稱,很簡單,這裡不再貼出了。 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.