您的位置:首页 > 其它

POI中HSSF和XSSF操作Excel

2013-08-05 20:10 615 查看

POI中HSSF和XSSF操作Excel

在公司实习快一个月了,这段时间公司业务要用JAVA操作复杂的Excel报表.刚开始的Excel还好,没有涉及到复杂的图表,所以使用JXL操作Excel,但是到后来涉及到复杂的图表和单元格公式后JXL就显得无力了.

公司业务需要在原有的Excel模板上填写从数据库读出来的数据,然后保存为新文件让客户下载.最后在业务的每个流程环节上添加签名图片,而且模板复杂所以只有使用Apache的POI来操作Excel.

在刚接触使用POI时,因为Excel模板格式是用的97-2003的板式(后缀名是.xls),所以使用HSSF来操作Excel,我很傻很天真的认为是Apache的幽默把微软的老版Excel称为HorribleSpreadSheetFormat,即"讨厌的电子表格格式",后来我才慢慢发现了HSSF操作有多张图表的Excel也很让人郁闷.

首先是HSSF读取Excel



publicclassExcelEditor{
privateHSSFWorkbookbook;
privateStringexcelRealPath;

publicExcelEditor(StringexcelRealPath)throwsIOException{
this.excelRealPath=excelRealPath;
FileInputStreamfis=newFileInputStream(excelRealPath);
book=newHSSFWorkbook(bis);
fis.close();
}
}



但是有时候在读取的时候会抛出Unabletoreadentireblock;0bytesread;expected512bytes异常,而且到现在没有发现一个好的解决方案,最后拜托谷老师,找到了一个解决方案:

publicclassExcelEditor{
privateHSSFWorkbookbook;
privateStringexcelRealPath;

publicExcelEditor(StringexcelRealPath)throwsIOException{
this.excelRealPath=excelRealPath;
FileInputStreamfis=newFileInputStream(excelRealPath);
ByteArrayInputStreambis=this.converter(fis);

book=newHSSFWorkbook(bis);

bis.close();
fis.close();
}

/**
*@paramfis将文件流转换成字节流可以解决问题
*@return
*@throwsIOException
*/
privateByteArrayInputStreamconverter(FileInputStreamfis)
throwsIOException{
ByteArrayInputStreambyteArrayInputStream=null;
bytebuf[]=org.apache.commons.io.IOUtils.toByteArray(fis);
byteArrayInputStream=newByteArrayInputStream(buf);
returnbyteArrayInputStream;
}
}
像这样转一道流解决了抛异常的问题,没有经过长时间测试,我的操作类为:

publicclassExcelEditor{
privateHSSFWorkbookbook;
privateStringexcelRealPath;
privateMap<Integer,ExcelSheet>sheets=newHashMap<Integer,ExcelSheet>();

publicExcelEditor(StringexcelRealPath)throwsIOException{
this.excelRealPath=excelRealPath;
FileInputStreamfis=newFileInputStream(excelRealPath);
ByteArrayInputStreambis=this.converter(fis);

book=newHSSFWorkbook(bis);

bis.close();
fis.close();
}
/***@paramfis将文件流转换成字节流可以解决问题*@return*@throwsIOException*/
privateByteArrayInputStreamconverter(FileInputStreamfis)throwsIOException{
ByteArrayInputStreambyteArrayInputStream=null;
bytebuf[]=org.apache.commons.io.IOUtils.toByteArray(fis);
byteArrayInputStream=newByteArrayInputStream(buf);
returnbyteArrayInputStream;
}

publicHSSFWorkbookgetHSSFWorkbook(){
returnbook;
}

/**
*@paramindex將Sheet的操作和Workbook分离,在ExcelEditor中用一个Map保存Sheet的引用
*@return
*/
publicExcelSheetgetSheet(intindex){
validateSheetIndex(index);
ExcelSheetsheet;
if(sheets.containsKey(index)){
sheet=sheets.get(index);
}else{
sheet=newExcelSheet(book.getSheetAt(index));
sheets.put(index,sheet);
}
returnsheet;
}

privatevoidvalidateSheetIndex(intindex){
intlastSheetIx=book.getNumberOfSheets()-1;
if(index<0||index>lastSheetIx){
thrownewIllegalArgumentException("Sheetindex("+index+")isoutofrange(0.."+lastSheetIx+")");
}
}

publicvoidwriteExcel(Stringpath)throwsIOException{
FileOutputStreamout=newFileOutputStream(path);
book.write(out);
out.close();
}

publicvoidsave()throwsIOException{
this.writeExcel(excelRealPath);
}
}


ExcelEditer提供了基本的读取,保存等操作,而下面的ExcelSheet则提供了对Sheet的操作:



publicclassExcelSheet{
privateHSSFSheetsheet;

publicExcelSheet(HSSFSheetsheet){
this.sheet=sheet;
}

privateHSSFCellgetCell(introwNum,intcolumn){
HSSFRowrow=sheet.getRow(rowNum);
if(row==null){
row=sheet.createRow(rowNum);
}
HSSFCellc=row.getCell(column);
if(c==null){
c=row.createCell(column);
}
returnc;
}

publicvoidsetGraphic(BufferedImagebi,HSSFClientAnchoranchor,booleanresize)throwsIOException{
//anchor.setAnchorType(HSSFClientAnchor.DONT_MOVE_AND_RESIZE);
ByteArrayOutputStreambaos=newByteArrayOutputStream();
ImageIO.write(bi,"jpg",baos);
HSSFPatriarchprinter=this.sheet.createDrawingPatriarch();
HSSFPicturepicture=printer.createPicture(anchor,sheet.getWorkbook().addPicture(baos.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));
if(resize){
picture.resize();
}
baos.close();
}

publicHSSFCellsetString(intrownum,intcolumn,Stringvalue){
HSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicHSSFCellsetInt(intrownum,intcolumn,intvalue){
HSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicHSSFCellsetDouble(intrownum,intcolumn,doublevalue){
HSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicHSSFCellsetBoolean(intrownum,intcolumn,booleanvalue){
HSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicHSSFCellsetText(intrownum,intcolumn,RichTextStringvalue){
HSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicHSSFCellsetDate(intrownum,intcolumn,Datevalue){
HSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicHSSFCellsetCalendar(intrownum,intcolumn,Calendarvalue){
HSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}
}




这两个类对付一般的有单元格公式的Sheet没有问题,但是遇到图表麻烦就出现了.项目中有一个模板是这样的:





在向这个模板插入新图片时把原来图表的内容给弄不见了,而且把格式搞得一塌糊涂.之后发现是createDrawingPatriarch()这个方法的问题,在API中是这样解释的:

Createsthetop-leveldrawingpatriarch.Thiswillhavetheeffectofremovinganyexistingdrawingsonthissheet.Thismaythenbeusedtoaddgraphicsorcharts

没办法,调用这个方法会把Chart整个Remove掉,换一种方法调用getDrawingPatriarch(),结果发现一样的效果.

测试了一下午,依然没有发现解决的问题,到这个时候我总算体会到了这SeparateSheetFormat是如此的可怕,Apache的良苦用心啊..

最后只有把目光转向XSSF,XSSF是第二代的Excel格式,也是微软公司支持OpenDocumentFormat(开放式文档格式)的一个改版.其后缀名是.xlsx,最后那个X的含义貌似是代表XML吧.有同学不懂OpenDocumentFormat的请问谷老师.懂的同学把后缀名改为.zip然后解压出来你就豁然开朗了.

不扯那么远了,最终的两个类为:



publicclassExcelEditor{
privateXSSFWorkbookbook;
privateOPCPackageopc;
privateStringexcelRealPath;
privateMap<Integer,ExcelSheet>sheets=newHashMap<Integer,ExcelSheet>();

/**
*新版的采用OPCPackage作为文件操作类包括.xlsx和.docx都可以用这个类去读取文件
*@paramexcelRealPath
*@throwsIOException
*@throwsInvalidFormatException
*/
publicExcelEditor(StringexcelRealPath)throwsIOException,InvalidFormatException{
this.opc=OPCPackage.open(excelRealPath);
this.book=newXSSFWorkbook(opc);
this.excelRealPath=excelRealPath;
}

publicXSSFWorkbookgetXSSFWorkbook(){
returnbook;
}

publicExcelSheetgetSheet(intindex){
validateSheetIndex(index);
ExcelSheetsheet;
if(sheets.containsKey(index)){
sheet=sheets.get(index);
}else{
sheet=newExcelSheet(book.getSheetAt(index));
sheets.put(index,sheet);
}
returnsheet;
}

privatevoidvalidateSheetIndex(intindex){
intlastSheetIx=book.getNumberOfSheets()-1;
if(index<0||index>lastSheetIx){
thrownewIllegalArgumentException("Sheetindex("+index+")isoutofrange(0.."+lastSheetIx+")");
}
}

publicvoidwriteExcel(Stringpath)throwsFileNotFoundException,IOException{
FileexcelFile=newFile(path);

if(excelFile.exists()){
Stringextension;
StringfileName;

if(path.lastIndexOf(".")!=-1&&".xlsx".equalsIgnoreCase(path.substring(path.lastIndexOf(".")))){
extension=path.substring(path.lastIndexOf("."));
fileName=path.substring(0,path.lastIndexOf("."));
}else{
thrownewIOException("Xlsxfileoutputonly,checkyourpath!!!");
}

FiletempFile=newFile(fileName+"T"+extension);
FileOutputStreamfos=newFileOutputStream(tempFile);
book.write(fos);
fos.close();
opc.revert();
excelFile.delete();
tempFile.renameTo(newFile(path));
}else{
FileOutputStreamfos=newFileOutputStream(excelFile);
book.write(fos);
fos.close();
}
}

publicvoidsaveExcel()throwsIOException{
this.writeExcel(this.excelRealPath);
}
}




我在XSSFWorkbook中没有找到保存Excel的方法,之后在发现OPCPackage中发现了revert()和close()方法.revert()个是将打开的Excel还原,不保存任何的修改,close()则是保存已经修改的操作.

close()在第二天运行的时候无法正确保存文件,导致close()之后再打开抛出异常,问了谷老师也不知道是什么原因,最后只有把源文件还原revert()然后保存为新文件之后在删掉.

操作XSSFSheet的类为:

publicclassExcelSheet{
privateXSSFSheetsheet;

publicExcelSheet(XSSFSheetsheet){
this.sheet=sheet;
}

privateXSSFCellgetCell(introwNum,intcolumn){
XSSFRowrow=sheet.getRow(rowNum);
if(row==null){
row=sheet.createRow(rowNum);
}
XSSFCellc=row.getCell(column);
if(c==null){
c=row.createCell(column);
}
returnc;
}

publicvoidsetGraphicByAnchor(BufferedImagebi,XSSFClientAnchoranchor)throwsIOException{
//anchor.setAnchorType(XSSFClientAnchor.DONT_MOVE_AND_RESIZE);
ByteArrayOutputStreambaos=newByteArrayOutputStream();
ImageIO.write(bi,"jpg",baos);
XSSFDrawingprinter=this.sheet.createDrawingPatriarch();
XSSFPicturepicture=printer.createPicture(anchor,sheet.getWorkbook().addPicture(baos.toByteArray(),XSSFWorkbook.PICTURE_TYPE_JPEG));
picture.resize();
baos.close();
}

publicXSSFCellsetString(intrownum,intcolumn,Stringvalue){
XSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicXSSFCellsetInt(intrownum,intcolumn,intvalue){
XSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicXSSFCellsetDouble(intrownum,intcolumn,doublevalue){
XSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicXSSFCellsetBoolean(intrownum,intcolumn,booleanvalue){
XSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicXSSFCellsetText(intrownum,intcolumn,RichTextStringvalue){
XSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicXSSFCellsetDate(intrownum,intcolumn,Datevalue){
XSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}

publicXSSFCellsetCalendar(intrownum,intcolumn,Calendarvalue){
XSSFCellxcell=this.getCell(rownum,column);
xcell.setCellValue(value);
returnxcell;
}
}

@原文引入:http://www.cnblogs.com/rockcookies/archive/2012/05/15/2502169.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: