【问题标题】:Attempt to write an excel file with Apache POI causing OutOfMemoryError尝试使用 Apache POI 写入导致 OutOfMemoryError 的 excel 文件
【发布时间】:2011-12-07 14:54:38
【问题描述】:

我有一个编写 excel 文件的程序。 它使用 Apache POI 编写 excel 2007 文件(我有超过 256 个列,所以我必须使用它)。该程序有效。我已经在非常小的文件上对其进行了测试,但是如果我使用更多的行,它就会耗尽内存。

这是堆栈跟踪:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.io.ByteArrayOutputStream.write(Unknown Source)
    at org.apache.poi.openxml4j.opc.internal.MemoryPackagePartOutputStream.write(MemoryPackagePartOutputStream.java:88)
    at org.apache.xmlbeans.impl.store.Cursor._save(Cursor.java:590)
    at org.apache.xmlbeans.impl.store.Cursor.save(Cursor.java:2544)
    at org.apache.xmlbeans.impl.values.XmlObjectBase.save(XmlObjectBase.java:212)
    at org.apache.poi.xssf.usermodel.XSSFSheet.write(XSSFSheet.java:2480)
    at org.apache.poi.xssf.usermodel.XSSFSheet.commit(XSSFSheet.java:2439)
    at org.apache.poi.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:196)
    at org.apache.poi.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:200)
    at org.apache.poi.POIXMLDocument.write(POIXMLDocument.java:204)
    at model.Conversione.traduzioneFile(Conversione.java:219)
    at model.Main.scriviFile(Main.java:75)
    at model.Main.main(Main.java:51)

错误发生在我写“workbook.write(fileOut)”的行(根据堆栈跟踪),其中 fileOut 是 FileOutputStream。这意味着显然有足够的内存供所有 java 对象存储 excel 文件,但由于某种原因,当它写入硬盘时,它必须占用更多的内存。

只是告诉你,我已经尝试将 java 堆大小增加到 1 gig(通过添加 -Xms128m -Xmx1024m),但这似乎仍然不起作用。

帮助!哎哟


代码示例:

..

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.xssf.usermodel.XSSFWorkbook;

//I'M USING A DATABASE 
import DAO.EventoDAO;
import DAO.ParametroDAO;

public class Conversion {

public static void traduzioneFile(File read, File write){
    FileOutputStream fos=null;


    try {
        fos = new FileOutputStream(write);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    if (fos!=null) {

        try{

            Workbook wb = new XSSFWorkbook() ;

            Sheet sheet = wb.createSheet();

            //I'm reading from a table in a .txt file , converting values, and putting them in a table..

            FileInputStream fis;
            try {
                fis = new FileInputStream(fileLettura);
                InputStreamReader isr=new InputStreamReader(fis);
                BufferedReader br=new BufferedReader(isr);
                String line=br.readLine();

                //here there are some variables
                while(line!=null) {

                    Row row = null;
                    row=sheet.createRow((short)row_number);


                                            //arrayLinea contains all the words of the line
                    while (column_number<arrayLinea.length){
                    value=arrayLinea[column_number];
 //if value is ok i translate it and put it in a cell
                       row.createCell((short)contatoreColonne).setCellValue(value);
                                    contatoreColonne++                                  

                        }
                        //next line
                        linea=br.readLine();
                        row_line++;

                }



        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }catch (Exception ex){
            ex.printStackTrace();

        }


        wb.write(fos);
        fos.flush();
        fos.close();

    }catch (FileNotFoundException e){
    }catch (IOException e){
    }catch (Exception e){

    }

}
}

我希望它是可读的..但是我正在扫描每一行,每列翻译值列,将它们放入单元格中……那部分没问题..我用 systems.out.println 测试了它^^ 但是在最后一行说“翻译完成,开始写作”之后,就会发生错误..

【问题讨论】:

  • 向我们展示导致此问题的代码。
  • 好的..我正在编辑帖子,显示的代码比真实的更简单,因为它是一项相当复杂的工作的一部分:D ..
  • 你有没有试过在任务管理器中查看jvm的内存使用情况?您是否尝试设置 newGC(参见 java.sun.com/docs/hotspot/gc1.4.2/faq.html 或 acevedoalberto.wordpress.com/2009/01/16/jvmtuning)?你也可以试试 MAT 来检查现有堆是否有内存泄漏,它对你很有帮助
  • 您使用的是什么版本的 Apache POI?如果它不是 POI 3.8 beta 4(或最近的夜间版本),切换到那个有帮助吗?
  • 看过stackoverflow.com/a/5038492/701884这个关于SO的类似问题的答案?

标签: java excel memory apache-poi


【解决方案1】:

使用 POI 编写 .xlsx 文件会占用大量内存。 1 场演出可能还不够。

最近 Apache POI 引入了一个新的 API (SXSSF),它是一种用于编写 .xlsx 文件的流式实现。我自己还没有使用过,但也许这是你可以研究的。

【讨论】:

  • 我刚刚尝试过 - 用 SXSSFWorkbook() 换掉 XSSFWorkbook(),一切都立即完美运行,非常非常快。谢谢!
  • 注意自动大小列计算的限制:stackoverflow.com/a/49514411/458157@Turismo 谢谢:)
【解决方案2】:

尝试增加堆空间。

如果您使用的是 Eclipse,则右键单击您的项目文件夹选择运行方式->运行配置->参数选项卡。

在参数选项卡中,尝试设置这些参数,

-Xms 设置初始 Java 堆大小

-Xmx 设置最大Java堆大小

-Xss 设置java线程栈大小

例子:

-Xms1024M -Xmx1524M

然后运行程序。

我希望这应该可行。

抱歉这么晚回复:D

【讨论】:

    【解决方案3】:

    您应该放置一个调试断点并跟踪您的代码。

    我相信在某个地方存在一个永无止境的无限循环并导致 OOM 错误。

    【讨论】:

    • no ..编码部分没问题..我已经测试了好几次..但是如果文件包含超过特定数量的行(我会在一分钟内告诉你的数字,当我抓住它时:D)异常出现在 wb.write(fos)...
    • mmm.. 我无法修改列大小.. 我翻译的每个文件都有许多我不知道的列,但我必须处理它显示的每个列...
    • Excel 2003 是的...但是使用 XSSF 您可以创建 Excel 2007 和 2010 文件 ^^
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-05
    • 1970-01-01
    • 2023-01-29
    相关资源
    最近更新 更多