7

当我尝试运行下面的程序时,我得到一个 java.lang.OutOfMemoryError: GC 开销限制超出异常。该程序的主要方法访问'指定目录并遍历所有包含.xlsx的文件。这很好用,因为我在任何其他逻辑之前对其进行了测试。它调用 xlsx 的方法基本上将 xlsx 文件转换为 csv 并将其附加到现有文件中也可以正常工作。但是当我把它放在 for 循环中时,这就是我得到这个异常的时候。我猜它在打开 xlsx 并将其转换为 csv 及其打开第二个的时间之后会发生冲突,也许我必须以某种方式关闭这一行:

File inputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\"+nameOfFile);

这是我现在唯一的猜测,当循环的第二次迭代到来时,当这个文件干扰时。我正在使用 Apache POI 库来操作 excel 文件。提前致谢!

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelMan {

    public static void main(String[] args) throws FileNotFoundException {



        int i =0;


            File dir = new File("C:\\Users\\edennis.AD\\Desktop\\test\\");
            for (File child : dir.listFiles()) {

            //initializing whether the sheet sent to method is first or not, and //counting iterations for each time the for loop as run

            boolean firstSheet = true;  
            i++;

           String nameOfFile = child.getName();

           if (nameOfFile.contains(".xlsx")){   

            System.out.println(nameOfFile);

                if (i != 0)
                firstSheet = false;


                File inputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\"+nameOfFile);

                //  writing excel data to csv 
              File outputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\memb.csv");
              xlsx(inputFile, outputFile, firstSheet);


            }


          //  }

        }


    }




        static void xlsx(File inputFile, File outputFile, boolean firstSheet) {
            // For storing data into CSV files
            StringBuffer data = new StringBuffer();


            try {
                FileOutputStream fos = new FileOutputStream(outputFile, true);
                // Get the workbook object for XLSX file
                XSSFWorkbook wBook = new XSSFWorkbook(new FileInputStream(inputFile));
                // Get first sheet from the workbook


                XSSFSheet sheet = wBook.getSheetAt(7);
                Row row;
                Cell cell;
                // Iterate through each rows from first sheet
                java.util.Iterator<Row> rowIterator = sheet.iterator();

                while (rowIterator.hasNext()) {

                    if (firstSheet != true)
                        rowIterator.next();

                    row = rowIterator.next();

                    // For each row, iterate through each columns
                    java.util.Iterator<Cell> cellIterator = row.cellIterator();
                    while (cellIterator.hasNext()) {


                        cell = cellIterator.next();

                        switch (cell.getCellType()) {
                            case Cell.CELL_TYPE_BOOLEAN:
                                data.append(cell.getBooleanCellValue() + "^");

                                break;
                            case Cell.CELL_TYPE_NUMERIC:
                                data.append(cell.getNumericCellValue() + "^");

                                break;
                            case Cell.CELL_TYPE_STRING:
                                data.append(cell.getStringCellValue() + "^");
                                break;                            
                            case Cell.CELL_TYPE_BLANK:
                                data.append("" + "^");
                                break;
                            default:
                                data.append(cell + "^");

                        }


                    }
                    data.append("\r\n");

                }

                fos.write(data.toString().getBytes());
                fos.close();


            } catch (Exception ioe) {
                ioe.printStackTrace();
            }
        }



}

附加信息:

下面是堆栈跟踪

   MR.xlsx
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3039)
        at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3060)
        at org.apache.xmlbeans.impl.store.Locale$SaxHandler.startElement(Locale.java:3250)
        at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.reportStartTag(Piccolo.java:1082)
        at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseAttributesNS(PiccoloLexer.java:1802)
        at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseOpenTagNS(PiccoloLexer.java:1521)
        at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseTagNS(PiccoloLexer.java:1362)
        at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseXMLNS(PiccoloLexer.java:1293)
        at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseXML(PiccoloLexer.java:1261)
        at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.yylex(PiccoloLexer.java:4808)
        at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.yylex(Piccolo.java:1290)
        at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.yyparse(Piccolo.java:1400)
        at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.parse(Piccolo.java:714)
        at org.apache.xmlbeans.impl.store.Locale$SaxLoader.load(Locale.java:3439)
        at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1270)
        at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1257)
        at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:345)
        at org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument$Factory.parse(Unknown Source)
        at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:138)
        at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java:130)
        at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java:286)
        at org.apache.poi.POIXMLDocument.load(POIXMLDocument.java:159)
        at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:207)
        at ExcelMan.xlsx(ExcelMan.java:71)
        at ExcelMan.main(ExcelMan.java:47)

excel文件非常大,目录中大约有30个左右,最大的一个大约170 MB,我应该从POI更改这些文件大小吗?

4

2 回答 2

3

你的excel文件大小是多少?我曾经遇到过类似的问题,创建csvxls. 就我而言,我不得不切换到事件驱动模型,看看XSSF 和 SAX (Event API)。我也内存不足(与-Xmx8g

来自链接网站的报价:

HSSF 的进一步努力将集中在以下主要领域:

  • 性能:POI 目前对大型工作表使用大量内存。
于 2013-10-17T19:45:12.313 回答
1

文件不需要关闭。只要您不维护对它们的引用,它们就会在超出范围时被 GCd。

该行将if (i != 0)始终评估为真,因为您在达到此条件之前至少增加了变量 i 一次。因此 firstSheet 始终设置为 false。

线

File inputFile = new File("C:\\Users\\edennis.AD\\Desktop\\test\\"+nameOfFile);

正在创建新文件。但是,您已经拥有此路径的文件对象,由child

您总是在写入同一个文件,每次迭代初始目录子目录时都会重新创建一个文件对象和新的 FileOutputStream,即使所有写入都是对同一个文件。

您没有在 finally 块中关闭 FileOutputStream ,并且在错误条件下它可能无法正确关闭您的 FileOutputStream 。

除非您需要同步方法来构建字符串,否则请使用 StringBuilder 而不是 StringBuffer。

考虑使用 FileWriter 而不是中间的 StringBuilder。而不是写给 Builder 使用

PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(outputFile, true))))

而不是data.append使用writer.printwriter.println注意:PrintWriter 和 Buffered Writer 包装器不是绝对必要的,但很有用。

如果您参考 XSSFWorkbook javadocs 中的构造函数选项,您会看到它说“使用 InputStream 需要比使用文件更多的内存,因此如果文件可用,那么您应该改为执行“示例如下”之类的操作” http:// poi.apache.org/apidocs/org/apache/poi/xssf/usermodel/XSSFWorkbook.html#XSSFWorkbook(java.io.InputStream)

如果一切都失败了,增加堆大小可能是一个可行的解决方案。假设您没有比您当前正在测试的文件大得多的文件的潜力。在 Java 中增加堆大小

于 2013-10-17T20:47:33.887 回答