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
相关文章推荐
- POI操作Excel详解,HSSF和XSSF两种方式
- 【转:POI操作Excel详解,HSSF和XSSF两种方式】
- POI操作Excel详解---HSSF和XSSF两种方式
- POI操作Excel详解,HSSF和XSSF两种方式
- POI操作Excel详解,HSSF和XSSF两种方式
- POI3.5_HSSF_和XSSF_Excel操作快速入门
- POI中HSSF和XSSF操作Excel
- POI操作Excel详解,HSSF和XSSF两种方式
- POI操作Excel详解,HSSF和XSSF两种方式
- POI操作Excel---给单元格添加超链接(HSSF & XSSF & SXSSF)
- POI Workbook接口和HSSFWorkbook对象和XSSFWorkbook对象操作相应excel版本
- POI操作Excel详解,HSSF和XSSF两种方式
- POI操作Excel详解,HSSF和XSSF两种方式
- POI操作Excel详解,HSSF和XSSF两种方式
- POI操作Excel详解,HSSF和XSSF两种方式
- POI Workbook接口和HSSFWorkbook对象和XSSFWorkbook对象操作相应excel版本
- POI操作Excel详细解释,HSSF和XSSF两种方式
- POI Workbook接口和HSSFWorkbook对象和XSSFWorkbook对象操作相应excel版本
- POI操作Excel详解,HSSF和XSSF两种方式
- POI操作Excel详解,HSSF和XSSF两种方式