8

データベースにダンプする前に、Java を使用して Excel ファイルを検証しようとしています。

エラーを引き起こす私のコードスニペットは次のとおりです。

try {
    fis = new FileInputStream(file);
    wb = new XSSFWorkbook(fis);
    XSSFSheet sh = wb.getSheet("Sheet1");
    for(int i = 0 ; i < 44 ; i++){
        XSSFCell a1 = sh.getRow(1).getCell(i);
        printXSSFCellType(a1);
    }
    
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

ここに私が得るエラーがあります

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.ArrayList.<init>(Unknown Source)
    at java.util.ArrayList.<init>(Unknown Source)
    at org.apache.xmlbeans.impl.values.NamespaceContext$NamespaceContextStack.<init>(NamespaceContext.java:78)
    at org.apache.xmlbeans.impl.values.NamespaceContext$NamespaceContextStack.<init>(NamespaceContext.java:75)
    at org.apache.xmlbeans.impl.values.NamespaceContext.getNamespaceContextStack(NamespaceContext.java:98)
    at org.apache.xmlbeans.impl.values.NamespaceContext.push(NamespaceContext.java:106)
    at org.apache.xmlbeans.impl.values.XmlObjectBase.check_dated(XmlObjectBase.java:1273)
    at org.apache.xmlbeans.impl.values.XmlObjectBase.stringValue(XmlObjectBase.java:1484)
    at org.apache.xmlbeans.impl.values.XmlObjectBase.getStringValue(XmlObjectBase.java:1492)
    at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTCellImpl.getR(Unknown Source)
    at org.apache.poi.xssf.usermodel.XSSFCell.<init>(XSSFCell.java:105)
    at org.apache.poi.xssf.usermodel.XSSFRow.<init>(XSSFRow.java:70)
    at org.apache.poi.xssf.usermodel.XSSFSheet.initRows(XSSFSheet.java:179)
    at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:143)
    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 com.xls.validate.ExcelValidator.main(ExcelValidator.java:79)

.xlsx ファイルが 1 MB 未満の場合、これは問題なく機能します。

これは、私の .xlsx ファイルが約 5 ~ 10 MB であり、POI がシート全体を一度に JVM メモリにロードしようとするためだと理解しています。

可能な回避策は何ですか?

4

7 に答える 7

10

2 つのオプションがあります。オプション #1 - JVM ヒープのサイズを増やして、Java がより多くのメモリを使用できるようにします。UserModel コードを使用した POI 内の Excel ファイルの処理は DOM ベースであるため、ファイル全体 (解析されたフォームを含む) をメモリにバッファリングする必要があります。ヘルプを増やす方法については、このような質問をしてみてください。

オプション #2、これは手間がかかります。イベント ベース (SAX) 処理に切り替えます。これは一度にファイルの一部しか処理しないため、必要なメモリがはるかに少なくなります。ただし、それにはより多くの作業が必要です。そのため、問題にさらに数 GB のメモリを投入したほうがよい場合があります。メモリは安価ですが、プログラマーはそうではありません! SpreadSheetのハウツー ページには、.xlsx ファイルの SAX 解析を実行する方法が説明されています。また、POI が提供するさまざまなサンプル ファイルがアドバイスとして参照できます。

.

また、別のこと-ストリームを介してファイルをロードしているようです。これは、さらに多くのものをメモリにバッファリングする必要があることを意味するため、悪いことです。ファイルを直接操作する方法など、この の詳細については、POI ドキュメントを参照してください。

于 2013-08-09T15:04:09.907 に答える
2

メモリ関連の問題には、POI の SXSSF ワークブックを使用できます。ここを参照

複数の CSV を読み取って単一の XLSX ファイルにマージしているときに、同様の問題に直面しました。それぞれ 30,000 行で合計 90,000 の合計 3 つの csv シートがありました。

以下のようにSXSFFを使用することで解決しました。

    public static void mergeCSVsToXLSX(Long jobExecutionId, Map<String, String> csvSheetNameAndFile, String xlsxFile) {
    try (SXSSFWorkbook wb = new SXSSFWorkbook(100);) { // keep 100 rows in memory, exceeding rows will be flushed to
                                                       // disk
      csvSheetNameAndFile.forEach((sheetName, csv) -> {
        try (CSVReader reader = new CSVReader(new FileReader(csv))) {
          wb.setCompressTempFiles(true);
          SXSSFSheet sheet = wb.createSheet(sheetName);
          sheet.setRandomAccessWindowSize(100);

          String[] nextLine;
          int r = 0;
          while ((nextLine = reader.readNext()) != null) {
            Row row = sheet.createRow((short) r++);
            for (int i = 0; i < nextLine.length; i++) {
              Cell cell = row.createCell(i);
              cell.setCellValue(nextLine[i]);
            }
          }
        } catch (IOException ioException) {
          logger.error("Error in reading CSV file {} for jobId {} with exception {}", csv, jobExecutionId,
              ioException.getMessage());
        }
      });

      FileOutputStream out = new FileOutputStream(xlsxFile);
      wb.write(out);
      wb.dispose();
    } catch (IOException ioException) {
      logger.error("Error in creating workbook for jobId {} with exception {}", jobExecutionId,
          ioException.getMessage());
    }
  }
于 2019-03-09T21:56:24.510 に答える
1

を使用しEvent API (HSSF Only)ます。

イベント API は、ユーザー API よりも新しいものです。これは、低レベルの API 構造を少しだけ学習したい中級の開発者を対象としています。使い方は比較的簡単ですが、Excel ファイルの各部分の基本的な理解 (または学習する意欲) が必要です。提供される利点は、比較的小さなメモリ フットプリントで XLS を読み取ることができることです。

于 2013-08-09T13:58:17.630 に答える
-1

私もxlsxファイルの解析中にOOMの同じ問題に直面しました...2日間の闘争の後、本当に完璧な以下のコードを最終的に見つけました。

このコードは sjxlsx に基づいています。xlsx を読み取り、HSSF シートに格納します。

           [code=java] 
            // read the xlsx file
       SimpleXLSXWorkbook = new SimpleXLSXWorkbook(new File("C:/test.xlsx"));

        HSSFWorkbook hsfWorkbook = new HSSFWorkbook();

        org.apache.poi.ss.usermodel.Sheet hsfSheet = hsfWorkbook.createSheet();

        Sheet sheetToRead = workbook.getSheet(0, false);

        SheetRowReader reader = sheetToRead.newReader();
        Cell[] row;
        int rowPos = 0;
        while ((row = reader.readRow()) != null) {
            org.apache.poi.ss.usermodel.Row hfsRow = hsfSheet.createRow(rowPos);
            int cellPos = 0;
            for (Cell cell : row) {
                if(cell != null){
                    org.apache.poi.ss.usermodel.Cell hfsCell = hfsRow.createCell(cellPos);
                    hfsCell.setCellType(org.apache.poi.ss.usermodel.Cell.CELL_TYPE_STRING);
                    hfsCell.setCellValue(cell.getValue());
                }
                cellPos++;
            }
            rowPos++;
        }
        return hsfSheet;[/code]
于 2013-10-20T07:26:14.277 に答える