poi的XSSFWorkbook转SXSSFWorkbook发现的问题

Posted CS_草祭先生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poi的XSSFWorkbook转SXSSFWorkbook发现的问题相关的知识,希望对你有一定的参考价值。

1. 背景

        项目上需要对报表进行打印,前提是用户自己上传excel模板,设置页眉页脚及表格样式,由后端根据参数获取模板后和数据后,将数据写入excel中返回给前端转为pdf预览及打印。已有接口是用poi的SXSSFWorkbook操作excel,具体实现这篇文章已经说明。

        现在需求变更,需要根据用户在模板中设置的表达式,将数据继承模板中样式输出到excel表格中。这样能让用户自定义设置表格样式,而非系统给定默认样式。

2. 遇到的问题

        实现过程中,需要获取模板中已设置的excel,并循环所有行找到表达式填充数据。通过SXSSFWorkbook无法直接将流转换,只能先转换为XSSFWorkbook,再实例化SXSSFWorkbook。具体请看上面提到的文章内容

XSSFWorkbook workbook = new XSSFWorkbook(file1);
// 转换为SXSSFWorkbook
SXSSFWorkbook wbook = new SXSSFWorkbook(workbook);

使用wbook.getSheetAt(0).getLastRowNum()却无法获取模板中设置的最后行号。查看源码

    public SXSSFWorkbook(XSSFWorkbook workbook)
    	this(workbook, DEFAULT_WINDOW_SIZE);
    

而使用workbook.getSheetAt(0).getLastRowNum()却能获取到。

而且有点难受的是,使用wbook.getSheetAt(0).getRow(0)获取到的为null,而使用wbook.getSheetAt(0).createRow(0)想去创建新行覆盖的时候又抛出异常,原因看以下源码

    /**
     * Create a new row within the sheet and return the high level representation
     *
     * @param rownum  row number
     * @return high level Row object representing a row in the sheet
     * @throws IllegalArgumentException If the max. number of rows is exceeded or 
     *      a rownum is provided where the row is already flushed to disk.
     * @see #removeRow(Row)
     */
    @Override
    public SXSSFRow createRow(int rownum)
    
        int maxrow = SpreadsheetVersion.EXCEL2007.getLastRowIndex();
        if (rownum < 0 || rownum > maxrow) 
            throw new IllegalArgumentException("Invalid row number (" + rownum
                    + ") outside allowable range (0.." + maxrow + ")");
        

        // attempt to overwrite a row that is already flushed to disk
        if(rownum <= _writer.getLastFlushedRow() ) 
            throw new IllegalArgumentException(
                    "Attempting to write a row["+rownum+"] " +
                    "in the range [0," + _writer.getLastFlushedRow() + "] that is already written to disk.");
        

        // attempt to overwrite a existing row in the input template
        if(_sh.getPhysicalNumberOfRows() > 0 && rownum <= _sh.getLastRowNum() ) 
            throw new IllegalArgumentException(
                    "Attempting to write a row["+rownum+"] " +
                            "in the range [0," + _sh.getLastRowNum() + "] that is already written to disk.");
        

        SXSSFRow newRow = new SXSSFRow(this);
        _rows.put(rownum, newRow);
        allFlushed = false;
        if(_randomAccessWindowSize >= 0 && _rows.size() > _randomAccessWindowSize) 
            try 
               flushRows(_randomAccessWindowSize);
             catch (IOException ioe) 
                throw new RuntimeException(ioe);
            
        
        return newRow;
    

代码走到第三个if的时候被逮住住抛出异常,真正有数据的是_sh,而不是_rows。但代码又不能获取到_sh

吐槽一下:无法理解写这个工具类的开发是怎么思考问题的,既让我们用,用起来又很难受

3. 解决方案

如果没有版本要求,时间也不够充裕,还是降低版本,使用XSSFWorkbook操作excel吧,懒得去纠结了,更有可能需要降低到HSSFWorkbook。反正操作方式基本相同,只是兼容的excel有些出入而已。

如果一定需要使用SXSSFWorkbook,那就去研究研究代码,看看如何解决这些问题。本人迫于时间紧任务重,只能委曲求全降低版本先实现功能了。

使用最新的POI3.11时,在运行 XSSFWorkbook workBook = new XSSFWorkbook ();这段代码时出现错误:

使用最新的POI3.11时,在运行

XSSFWorkbook  workBook = new XSSFWorkbook ();这段代码时出现错误:

技术分享

 

XMLEventFactory.newFactory()这个API是在JDK 1.6.0.18加入的,我当时是用MyEclipse 10运行编译的,而
MyEclipse 10 会用自带的jdk编译,而自带的是 1.6.0.13;
然后我把MyEclipse 的jdk环境设置成了1.7不用默认的jdk编译;问题得到解决;

技术分享


技术分享

 


以上是关于poi的XSSFWorkbook转SXSSFWorkbook发现的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在POI XSSFWorkbook中消除零值数据条

Java-API-POI-Excel:XSSFWorkbook Documentation

收藏poi 使用模板创建一个XSSFWorkbook,为啥取不到row对象

org.apache.poi.hssf.usermodel.HSSFWorkbookorg.apache.poi.xssf.usermodel.XSSFWorkbook excel2003 exce

使用POI操作Excel时new XSSFWorkbook ()报错java.lang.NoSuchMethodError解决方式

XSSFWorkbook实现导出excel