1 对象结构图
结构看,这个设计是合理的;将2003、2007的不同实现通过接口连接起来;但是,在写demo的时候感觉相对JXL,POI更难以上手;JXL小巧,简单,好用;特别是对单元格复制的时候、还有选择单元格等;POI不支持复用已有的格式,而JXL只要new
WritableCellFormat(cells.getCellFormat())将读取的格式转换为写入的格式即可;当然,根本原因不是因为POI的设计有问题;而是,2003与2007的两种文件格式完全不同,所以导致POI代码是两份合并的;因此,从工作簿到单元格到单元格样式,都是截然不同的两份;所以,POI就不能提供面向对象那种将原有的一个单元格或者一个单元格格式直接复制到另一个工作表中;而是,在另一个工作表中新建,然后将之前的工作表的单元格属性一个一个复制,相当于重新建立了一份;这点对操作者来说,是麻烦的事情;但是,目前市场上并没有比这更好的选择了;
然后,对应Office软件的更新,JXL原本出发点应该是只提供对Excel的快速开发而设计的;而2007版本以后,文件格式不同了,JXL无法解析2007以后的版本;估计JXL是不会去升级了,因为完全没有必要花这个代价;而POI是对Office家族的整体做了封装,以后也会继续升级;
所以,以后项目里面只使用POI,JXL就放弃吧;
2 demo如下
package myTest;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Date;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
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.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class POITest {
private static Logger logger =
LoggerFactory.getLogger(POITest.class);
// 读取测试
public static void testRead(String filePath)
throws Exception {
Workbook workBook = null;
InputStream fin = null;
try {
fin = new
FileInputStream(filePath);
workBook =
WorkbookFactory.create(fin);
logger.info("Workbook
Class: {}", workBook.getClass().getName());
int sheetNum
= workBook.getNumberOfSheets();
for (int
index=0; index
loop
Sheet
sheet = workBook.getSheetAt(index);
int
rows = getValidRowIndex(sheet);
logger.info("sheet
name: {}, sheet rows: {}, valid rows: {}",
new
Object[]{sheet.getSheetName(), sheet.getLastRowNum(), rows});
for
(int rowIndex=0; rowIndex<=rows; ++rowIndex) { //
row loop
Row
row = sheet.getRow(rowIndex);
int
cells = row.getLastCellNum();
logger.info("=>
rows: {}, cells: {}", rowIndex, cells);
for
(int cellIndex=0; cellIndex<=cells; ++cellIndex) {
// cell loop
Cell
cell = row.getCell(cellIndex);
int
cellType = getCellType(cell);
Object
cellValue = getCellValue(cell);
if
(cellValue instanceof Date) {
cellValue
= ((Date)cellValue).toLocaleString();
}
logger.info("=>
cell: {}, type:{}, value: {}", new Object[]{cellIndex, cellType,
cellValue});
}
}
}
} finally {
if (fin !=
null) {
fin.close();
}
}
}
// 获得有效的行标(注:第一列必须不能为空)
public static int getValidRowIndex(Sheet sheet)
{
int lastRow =
sheet.getLastRowNum();
int rowIndex = 0;
for (rowIndex=lastRow;
rowIndex>0; --rowIndex) {
Cell cell =
sheet.getRow(rowIndex).getCell(0);
if (cell ==
null) {
continue;
}
int cellType
= cell.getCellType();
if
(Cell.CELL_TYPE_BLANK != cellType) {
break;
}
}
return rowIndex;
}
// 获取单元格内容
public static Object getCellValue(Cell cell)
{
Object result = null;
if (cell == null) {
return
result;
}
int type =
cell.getCellType();
switch(type) {
case
Cell.CELL_TYPE_NUMERIC:
double value
= cell.getNumericCellValue();
if
(org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))
{
result
= org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value);
} else
{
result
= value;
}
break;
case
Cell.CELL_TYPE_STRING:
result =
cell.getStringCellValue();
break;
case
Cell.CELL_TYPE_FORMULA:
cell.setCellType(Cell.CELL_TYPE_NUMERIC);
result =
cell.getNumericCellValue();
break;
case
Cell.CELL_TYPE_BLANK:
break;
case
Cell.CELL_TYPE_BOOLEAN: