使用Apache POI读取Excel文件

jopen 11年前

摘要: 适用于Microsoft Excel xls/xlsx两种类型电子表格的读取操作。

        网上关于介绍Apache POI操作Excel的文章已经很多了,但都讲得比较复杂。poi的API 与实际使用中的Excel很类似,可以说是POI把Excel中的workbook、sheet、cell等对象化了,在实际使用中极易理解。但由于Apache POI在存在已有不短时间,至少在excel2007之前就已经出现,造成同样一套Api并不能同时读取(写入)xls和xlsx两种类型的Excel文件。但poi对excel有一个很好的抽象(ss包下的Workbook、Sheet、Cell等类),可以一定程度上忽略xls/xlsx的处理细节,针对其通用部分进行处理,但如果需要对各自有理强的支持,还是建议使用相应的API。

    Apache POI 各个包功能描述:

        HSSF - 提供读写Microsoft Excel XLS格式档案的功能。
        XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
        HWPF - 提供读写Microsoft Word DOC格式档案的功能。
        HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
        HDGF - 提供读Microsoft Visio格式档案的功能。
        HPBF - 提供读Microsoft Publisher格式档案的功能。
        HSMF - 提供读Microsoft Outlook格式档案的功能。

下面给出一个简单的实现Demo:

[ExcelReader]

package net.yeah.likun_zhang.excel;    import static net.yeah.likun_zhang.util.Debug.printf;    import java.io.FileInputStream;  import java.io.IOException;  import java.text.SimpleDateFormat;  import java.util.ArrayList;  import java.util.List;    import net.yeah.likun_zhang.util.Debug;    import org.apache.commons.lang3.StringUtils;  import org.apache.poi.hssf.usermodel.HSSFDateUtil;  import org.apache.poi.hssf.usermodel.HSSFWorkbook;  import org.apache.poi.ss.usermodel.Cell;  import org.apache.poi.ss.usermodel.Row;  import org.apache.poi.ss.usermodel.Sheet;  import org.apache.poi.ss.usermodel.Workbook;  import org.apache.poi.xssf.usermodel.XSSFWorkbook;    /**   * 读取Excel 97~2003 xls格式 /2007~ xlsx格式   * @author  ZhangLiKun   * @mail  likun_zhang@yeah.net   * @date  2013-5-11   */  public class ExcelReader {     /**    * 创建工作簿对象    * @param filePath    * @return    * @throws IOException    * @date 2013-5-11    */   public static final Workbook createWb(String filePath) throws IOException {    if(StringUtils.isBlank(filePath)) {     throw new IllegalArgumentException("参数错误!!!") ;    }    if(filePath.trim().toLowerCase().endsWith("xls")) {     return new HSSFWorkbook(new FileInputStream(filePath)) ;    } else if(filePath.trim().toLowerCase().endsWith("xlsx")) {     return new XSSFWorkbook(new FileInputStream(filePath)) ;    } else {     throw new IllegalArgumentException("不支持除:xls/xlsx以外的文件格式!!!") ;    }   }      public static final Sheet getSheet(Workbook wb ,String sheetName) {    return wb.getSheet(sheetName) ;   }      public static final Sheet getSheet(Workbook wb ,int index) {    return wb.getSheetAt(index) ;   }      public static final List<Object[]> listFromSheet(Sheet sheet) {        int rowTotal = sheet.getPhysicalNumberOfRows() ;    Debug.printf("{}共有{}行记录!" ,sheet.getSheetName() ,rowTotal) ;        List<Object[]> list = new ArrayList<Object[]>() ;    for(int r = sheet.getFirstRowNum() ; r <= sheet.getLastRowNum() ; r ++) {     Row row = sheet.getRow(r) ;     if(row == null)continue ;     // 不能用row.getPhysicalNumberOfCells(),可能会有空cell导致索引溢出     // 使用row.getLastCellNum()至少可以保证索引不溢出,但会有很多Null值,如果使用集合的话,就不说了     Object[] cells = new Object[row.getLastCellNum()] ;      for(int c = row.getFirstCellNum() ; c <= row.getLastCellNum() ; c++) {      Cell cell = row.getCell(c) ;      if(cell == null)continue ;      cells[c] = getValueFromCell(cell) ;     }     list.add(cells) ;    }        return list ;   }         /**    * 获取单元格内文本信息    * @param cell    * @return    * @date 2013-5-8    */   public static final String getValueFromCell(Cell cell) {    if(cell == null) {     printf("Cell is null !!!") ;     return null ;    }    String value = null ;    switch(cell.getCellType()) {     case Cell.CELL_TYPE_NUMERIC : // 数字      if(HSSFDateUtil.isCellDateFormatted(cell)) {  // 如果是日期类型       value = new SimpleDateFormat(DatePattern.LOCALE_ZH_DATE.getValue()).format(cell.getDateCellValue()) ;      } else  value = String.valueOf(cell.getNumericCellValue()) ;      break ;     case Cell.CELL_TYPE_STRING:  // 字符串      value = cell.getStringCellValue() ;      break ;     case Cell.CELL_TYPE_FORMULA: // 公式      // 用数字方式获取公式结果,根据值判断是否为日期类型      double numericValue = cell.getNumericCellValue() ;      if(HSSFDateUtil.isValidExcelDate(numericValue)) { // 如果是日期类型       value = new SimpleDateFormat(DatePattern.LOCALE_ZH_DATE.getValue()).format(cell.getDateCellValue()) ;      } else  value = String.valueOf(numericValue) ;      break ;     case Cell.CELL_TYPE_BLANK:    // 空白      value = ExcelConstants.EMPTY_CELL_VALUE ;      break ;     case Cell.CELL_TYPE_BOOLEAN:   // Boolean      value = String.valueOf(cell.getBooleanCellValue()) ;      break ;     case Cell.CELL_TYPE_ERROR:    // Error,返回错误码      value = String.valueOf(cell.getErrorCellValue()) ;      break ;     default:value = StringUtils.EMPTY ;break ;    }    // 使用[]记录坐标    return value + "["+cell.getRowIndex()+","+cell.getColumnIndex()+"]" ;   }      }

 测试类[ExcelReaderTest]

package net.yeah.likun_zhang.excel;    import java.io.FileNotFoundException;  import java.io.IOException;  import java.util.List;    import net.yeah.likun_zhang.BaseTest;  import net.yeah.likun_zhang.util.Debug;  import net.yeah.likun_zhang.util.ToString;    import org.apache.commons.lang3.StringUtils;  import org.apache.poi.ss.usermodel.Sheet;  import org.apache.poi.ss.usermodel.Workbook;  import org.junit.Test;    /**   * 读取   * @author  ZhangLiKun   * @mail  likun_zhang@yeah.net   * @date  2013-5-8   */  public class ExcelReaderTest extends BaseTest{     @Test   public void testRead() throws FileNotFoundException, IOException {    Workbook wb = ExcelReader.createWb("src/main/resources/excels/demo-3.xlsx") ;        // 获取Workbook中Sheet个数    int sheetTotal = wb.getNumberOfSheets() ;    Debug.printf("工作簿中的工作表个数为:{}" ,sheetTotal);        // 获取Sheet    Sheet sheet = ExcelReader.getSheet(wb, 0) ;        // 遍历Sheet    List<Object[]> list = ExcelReader.listFromSheet(sheet) ;    Debug.printf(list, new ToString<Object[]>(){     private int index = 1 ;      @Override     public String toString(Object[] t) {            if(t == null || t.length == 0)return StringUtils.EMPTY ;      StringBuffer sb = new StringBuffer(index ++ + ":") ;      for(int i = 0 ,len = t.length ; i < len ; i++) {       sb.append(t[i] + ",") ;      }      return sb.toString();     }    }) ;       }     }

测试辅助类[Debug]

package net.yeah.likun_zhang.util;    import java.util.Collection;  import java.util.Iterator;    import org.apache.commons.lang3.ArrayUtils;    /**   * Debug函数库   * @author  ZhangLiKun   * @mail  likun_zhang@yeah.net   * @date  2013-5-8   */  public class Debug {     /**    * 打印函数    * @param objects    * @date 2013-5-8    */   public static final void printf(String msg ,Object ...objects) {    if(ArrayUtils.isEmpty(objects)) {     System.out.println(msg);     return ;    }    for(int i = 0 ,len = objects.length ; i < len ; i ++) {     Object obj = objects[i] ;     msg = msg.replaceFirst("\\{\\}", obj == null ? "" : obj.toString()) ;    }    System.out.println(msg);   }      /**    * 打印函数    * @param obj    * @date 2013-5-8    */   public static final void printf(Object obj) {    if(obj != null){     System.out.println(obj.toString());    }   }       /**    * 打印集合    * @param list    * @param ts    * @date 2013-5-8    */   public static final <T> void printf(Collection<T> list ,ToString<T> ts) {    if(list == null || list.isEmpty()) return ;    Iterator<T> iter = list.iterator() ;    while(iter.hasNext()) {     T t = iter.next() ;  //   if(t == null)continue ;     if(ts == null) {      System.out.println(t.toString());     } else {      String msg = ts.toString(t) ;  //    if(msg != null) {       System.out.println(msg);  //    }     }    }   }     }