POI中HSSF和XSSF操作Excel

 

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

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

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

首先是HSSF读取Excel

 
public class ExcelEditor {
private HSSFWorkbook book;
private String excelRealPath; public ExcelEditor(String excelRealPath)throws IOException{
this.excelRealPath = excelRealPath;
FileInputStream fis = new FileInputStream(excelRealPath);
book = new HSSFWorkbook(bis);
fis.close();
}
}
 

但是有时候在读取的时候会抛出Unable to read entire block;0 bytes read; expected 512 bytes 异常,而且到现在没有发现一个好的解决方案,最后拜托谷老师,找到了一个解决方案:

public class ExcelEditor {
private HSSFWorkbook book;
private String excelRealPath; public ExcelEditor(String excelRealPath) throws IOException {
this.excelRealPath = excelRealPath;
FileInputStream fis = new FileInputStream(excelRealPath);
ByteArrayInputStream bis = this.converter(fis); book = new HSSFWorkbook(bis); bis.close();
fis.close();
} /**
* @param fis 将文件流转换成字节流可以解决问题
* @return
* @throws IOException
*/
private ByteArrayInputStream converter(FileInputStream fis)
throws IOException {
ByteArrayInputStream byteArrayInputStream = null;
byte buf[] = org.apache.commons.io.IOUtils.toByteArray(fis);
byteArrayInputStream = new ByteArrayInputStream(buf);
return byteArrayInputStream;
}
}
像这样转一道流解决了抛异常的问题,没有经过长时间测试,我的操作类为: public class ExcelEditor {
private HSSFWorkbook book;
private String excelRealPath;
private Map<Integer,ExcelSheet> sheets = new HashMap<Integer,ExcelSheet>(); public ExcelEditor(String excelRealPath)throws IOException{
this.excelRealPath = excelRealPath;
FileInputStream fis = new FileInputStream(excelRealPath);
ByteArrayInputStream bis = this.converter(fis); book = new HSSFWorkbook(bis); bis.close();
fis.close();
}
/** * @param fis 将文件流转换成字节流可以解决问题 * @return * @throws IOException */
private ByteArrayInputStream converter(FileInputStream fis) throws IOException {
ByteArrayInputStream byteArrayInputStream = null;
byte buf[] = org.apache.commons.io.IOUtils.toByteArray(fis);
byteArrayInputStream = new ByteArrayInputStream(buf);
return byteArrayInputStream;
} public HSSFWorkbook getHSSFWorkbook(){
return book;
} /**
* @param index 將Sheet的操作和Workbook分离,在ExcelEditor中用一个Map保存Sheet的引用
* @return
*/
public ExcelSheet getSheet(int index){
validateSheetIndex(index);
ExcelSheet sheet;
if(sheets.containsKey(index)){
sheet = sheets.get(index);
}else{
sheet = new ExcelSheet(book.getSheetAt(index));
sheets.put(index, sheet);
}
return sheet;
} private void validateSheetIndex(int index) {
int lastSheetIx = book.getNumberOfSheets() - 1;
if (index < 0 || index > lastSheetIx) {
throw new IllegalArgumentException("Sheet index ("+ index +") is out of range (0.." + lastSheetIx + ")");
}
} public void writeExcel(String path) throws IOException{
FileOutputStream out = new FileOutputStream(path);
book.write(out);
out.close();
} public void save() throws IOException{
this.writeExcel(excelRealPath);
}
}

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

 
public class ExcelSheet {
private HSSFSheet sheet; public ExcelSheet(HSSFSheet sheet) {
this.sheet = sheet;
} private HSSFCell getCell(int rowNum, int column) {
HSSFRow row = sheet.getRow(rowNum);
if (row == null) {
row = sheet.createRow(rowNum);
}
HSSFCell c = row.getCell(column);
if (c == null) {
c = row.createCell(column);
}
return c;
} public void setGraphic(BufferedImage bi, HSSFClientAnchor anchor,boolean resize) throws IOException {
// anchor.setAnchorType(HSSFClientAnchor.DONT_MOVE_AND_RESIZE);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bi, "jpg", baos);
HSSFPatriarch printer = this.sheet.createDrawingPatriarch();
HSSFPicture picture = printer.createPicture(anchor, sheet.getWorkbook().addPicture(baos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));
if (resize) {
picture.resize();
}
baos.close();
} public HSSFCell setString(int rownum, int column, String value) {
HSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public HSSFCell setInt(int rownum, int column, int value) {
HSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public HSSFCell setDouble(int rownum, int column, double value) {
HSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public HSSFCell setBoolean(int rownum, int column, boolean value) {
HSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public HSSFCell setText(int rownum, int column, RichTextString value) {
HSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public HSSFCell setDate(int rownum, int column, Date value) {
HSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public HSSFCell setCalendar(int rownum, int column, Calendar value) {
HSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
}
}
 

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

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

Creates the top-level drawing patriarch. This will have the effect of removing any existing drawings on this sheet. This may then be used to add graphics or charts

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

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

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

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

 
public class ExcelEditor {
private XSSFWorkbook book;
private OPCPackage opc;
private String excelRealPath;
private Map<Integer,ExcelSheet> sheets = new HashMap<Integer,ExcelSheet>(); /**
* 新版的采用OPCPackage作为文件操作类包括.xlsx和.docx都可以用这个类去读取文件
* @param excelRealPath
* @throws IOException
* @throws InvalidFormatException
*/
public ExcelEditor(String excelRealPath)throws IOException, InvalidFormatException {
this.opc = OPCPackage.open(excelRealPath);
this.book = new XSSFWorkbook(opc);
this.excelRealPath = excelRealPath;
} public XSSFWorkbook getXSSFWorkbook(){
return book;
} public ExcelSheet getSheet(int index){
validateSheetIndex(index);
ExcelSheet sheet;
if(sheets.containsKey(index)){
sheet = sheets.get(index);
}else{
sheet = new ExcelSheet(book.getSheetAt(index));
sheets.put(index, sheet);
}
return sheet;
} private void validateSheetIndex(int index) {
int lastSheetIx = book.getNumberOfSheets() - 1;
if (index < 0 || index > lastSheetIx) {
throw new IllegalArgumentException("Sheet index ("+ index +") is out of range (0.." + lastSheetIx + ")");
}
} public void writeExcel(String path) throws FileNotFoundException,IOException {
File excelFile = new File(path); if(excelFile.exists()){
String extension;
String fileName; if(path.lastIndexOf(".")!=-1 && ".xlsx".equalsIgnoreCase(path.substring(path.lastIndexOf(".")))){
extension = path.substring(path.lastIndexOf("."));
fileName = path.substring(0,path.lastIndexOf("."));
}else{
throw new IOException("Xlsx file output only,check your path!!!");
} File tempFile = new File(fileName+"T"+extension);
FileOutputStream fos = new FileOutputStream(tempFile);
book.write(fos);
fos.close();
opc.revert();
excelFile.delete();
tempFile.renameTo(new File(path));
}else{
FileOutputStream fos = new FileOutputStream(excelFile);
book.write(fos);
fos.close();
}
} public void saveExcel() throws IOException{
this.writeExcel(this.excelRealPath);
}
}
 

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

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

操作XSSFSheet的类为:

public class ExcelSheet{
private XSSFSheet sheet; public ExcelSheet(XSSFSheet sheet){
this.sheet = sheet;
} private XSSFCell getCell(int rowNum, int column) {
XSSFRow row = sheet.getRow(rowNum);
if (row == null) {
row = sheet.createRow(rowNum);
}
XSSFCell c = row.getCell(column);
if (c == null) {
c = row.createCell(column);
}
return c;
} public void setGraphicByAnchor(BufferedImage bi,XSSFClientAnchor anchor)throws IOException {
// anchor.setAnchorType(XSSFClientAnchor.DONT_MOVE_AND_RESIZE);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bi,"jpg", baos);
XSSFDrawing printer = this.sheet.createDrawingPatriarch();
XSSFPicture picture = printer.createPicture(anchor, sheet.getWorkbook().addPicture(baos.toByteArray(),XSSFWorkbook.PICTURE_TYPE_JPEG));
picture.resize();
baos.close();
} public XSSFCell setString(int rownum, int column, String value) {
XSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public XSSFCell setInt(int rownum, int column, int value) {
XSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public XSSFCell setDouble(int rownum, int column, double value) {
XSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public XSSFCell setBoolean(int rownum, int column, boolean value) {
XSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public XSSFCell setText(int rownum, int column, RichTextString value) {
XSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public XSSFCell setDate(int rownum, int column, Date value) {
XSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
} public XSSFCell setCalendar(int rownum, int column, Calendar value) {
XSSFCell xcell = this.getCell(rownum, column);
xcell.setCellValue(value);
return xcell;
}
} @原文引入:http://www.cnblogs.com/rockcookies/archive/2012/05/15/2502169.html

POI中HSSF和XSSF操作Excel的更多相关文章

  1. HSSF与XSSF导出excel文档

    Apache POI Apache POI 是用Java编写的免费开源的跨平台的 Java API,它可以创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文 ...

  2. 工作中常用的QTP操作Excel函数

    前言 本文只是对工作中常用的EOM相关函数的整理,并不是要写个大而全的操作手册,如果想对EOM有更多的了解可以参考QTP的帮助文档或查看QTP安装目录\CodeSamplesPlus\UsingExc ...

  3. Delphi中使用OLE方法操作Excel

    首先创建 Excel 对象,使用ComObj: var ExcelApp: Variant; ExcelApp := CreateOleObject( ′Excel.Application′ ); 注 ...

  4. java使用Apache POI操作excel文件

    官方介绍 HSSF is the POI Project's pure Java implementation of the Excel '97(-2007) file format. XSSF is ...

  5. C# 操作 Excel 文件(.xls 或 .xlsx)

    在.net中,常用的操作excel文件的方式,有三种: OLE DB的形式, 第三方框架NPOI, Office组件. 总结: 通过对比,在读取大数据量的excel文件,建议用OLE DB的形式,把e ...

  6. 关于 HSSF 和 XSSF 功能的开发者入门指南 (Apache POI 操作 Excel)

    关于 HSSF 和 XSSF 功能的开发者入门指南 笔者深夜无眠,特此对本文翻译一部分,未完成部分待后续更新 本文源文地址 意欲使用 HSSF 和 XSSF 功能快熟读写电子表格?那本文就是为你而写的 ...

  7. POI操作Excel详细解释,HSSF和XSSF两种方式

    HSSF道路: package com.tools.poi.lesson1; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  8. POI操作Excel详解,HSSF和XSSF两种方式

    package com.tools.poi.lesson1; import java.io.FileInputStream; import java.io.FileNotFoundException; ...

  9. poi操作officePOI操作excel中的数据格式(日期类型)

    7.3.3 POI中Excel文件Cell的类型 在读取每一个Cell的值的时候,通过getCellType方法获得当前Cell的类型,在Excel中Cell有6种类型,如表7-3所示. 表7-3 C ...

随机推荐

  1. 大数据学习——采集文件到HDFS

    采集需求:比如业务系统使用log4j生成的日志,日志内容不断增加,需要把追加到日志文件中的数据实时采集到hdfs 根据需求,首先定义以下3大要素 l  采集源,即source——监控文件内容更新 :  ...

  2. 大数据学习——HADOOP集群搭建

    4.1 HADOOP集群搭建 4.1.1集群简介 HADOOP集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起 HDFS集群: 负责海量数据的存储,集群中的角色主 ...

  3. sencha architect开发sencha touch应用注意事项

    以下说明文字针对sencha architect v2.2.2 一.无限期试用 1. 下载地址: http://www.sencha.com/products/architect/download/ ...

  4. Google SPDY

    SPDY(读作“SPeeDY”)是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验.SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强 ...

  5. Baby Step Giant Step model

    ******************************************** */ #include <stdio.h> #include <string.h> # ...

  6. HashMap排序的问题

    那么已知一个HashMap<Integer,User>集合, User有name(String)和 age(int)属性.请写一个方法实现对HashMap 的排序功能,该方法接收 Hash ...

  7. Java课堂测试--实现ATM的基本操作体会

    9月20的周四的Java课堂第一节课上就是有关于实现ATM的考试内容,在实现的过程中我了解到自己本身还是有很多的不足之处,例如在实现工程方面的相似性上面还有些许就的欠缺,再者就是回宿舍拿电源的原因导致 ...

  8. [MGR——Mysql的组复制之多主模式 ] 详细搭建部署过程

    组复制可以在两种模式下运行. 1.在单主模式下,组复制具有自动选主功能,每次只有一个 server成员接受更新.2.在多主模式下,所有的 server 成员都可以同时接受更新.   组复制与异步主从复 ...

  9. Windows平台下Git(gitblit)服务器搭建

    环境:Windows 10 专业版32位 因为公司服务器上已经搭了Visual SVN等,只好在Windows上搭个Git Server给大家用. 参考链接:http://www.cnblogs.co ...

  10. 解决安装oracle11g r2时提示pdksh conflicts with ksh-20100621-2.el6.i686问题

    http://blog.csdn.net/linghao00/article/details/7943740 http://www.2cto.com/os/201306/218566.html 在Ce ...