Apache POIで.xlsxファイルを処理中に問題が発生しています。私はStackOverflowのスレッドの多くを読んだだけでなく、IntellijとOracleのサイトでもサポートしています。推奨される修正を実装しようとしました。 JVMが5 MBを超えるファイルを処理しようとすると、メモリ不足エラーが発生します。参考までに、私は8GBのRAMを搭載したiMacを利用しており、JVMのRAM割り当てを現在の4GB(一度に512MB)のレベルまで上げました。Apache POI OutOfMemoryError
私が作成しているプログラムはすべて、ディレクトリ内のスプレッドシートを秀で、フィールドから一意の値をHashSetに追加します。結果のHashSetは、すべてのスプレッドシートが処理された後にファイルに書き込まれます。
ファイルが最初に処理されたファイルであるか最後に処理されたファイルであろうと、5 MBを超えるファイルが見つかると、GCは追い続けることができず、メモリ不足例外が発生します。エクセルファイルの読み込みと処理には5 MBの制限があるようです。奇妙に思えるのは、5 MBを少し上回るファイルがリソースのシステムに悪影響を及ぼすことになるので、問題が私のコードに含まれているのだろうかと思っていますか?以下の主な方法。思考?
public class Launcher {
public static void main(String[] args) {
WVDataFileReader reader = new WVDataFileReader();
HashSet<String> operators = reader.getOperatorsFromExcel("data/WV/production", 2);
FileOutput.writeToFile(operators, "/db/mysql/mysql-files/operators");
}
}
public abstract class RegulatoryDataFileReader {
private final String EXCEL_EXTENSION = "xlsx";
protected static final Logger LOGGER = Logger.getLogger(RegulatoryDataFileReader.class.getName());
protected abstract HashSet<String> processSheetForOperators(Sheet sheet, int firstDataRow, HashSet<String> set);
public HashSet<String> getOperatorsFromExcel(String directory, int firstDataRow) {
HashSet<String> temp = new HashSet<>();
ArrayList<File> spreadsheets = getExcelFiles(directory);
Collections.sort(spreadsheets);
for (File excelFile : spreadsheets) {
System.out.println("Reading data from " + excelFile.getName());
try {
Workbook workbook = WorkbookFactory.create(excelFile);
Sheet sheet = workbook.getSheetAt(0); // Assumes spreadsheet has 1 sheet
processSheetForOperators(sheet, firstDataRow, temp);
workbook.close();
} catch (FileNotFoundException e) {
LOGGER.log(Level.SEVERE, e.toString(), e);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.toString(), e);
} catch (InvalidFormatException e) {
LOGGER.log(Level.SEVERE, e.toString(), e);
}
}
return temp;
}
public class WVDataFileReader extends RegulatoryDataFileReader {
@Override
public HashSet<String> processSheetForOperators(Sheet sheet, int firstDataRow, HashSet<String> set) {
Iterator<Row> rowIterator = sheet.iterator();
if (rowIterator.hasNext()) {
// Skip to the first row containing data
for (int i = 1; i < firstDataRow; i++) {
rowIterator.next();
}
while (rowIterator.hasNext()) {
int columnNum = 0;
Row row = rowIterator.next(); // Advance row
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
columnNum++;
Cell cell = cellIterator.next(); // Advance cell
switch (columnNum) {
case 4:
cell.setCellType(Cell.CELL_TYPE_STRING);
String operator = cell.getStringCellValue();
operator = StrUtils.cleanString(operator);;
set.add(operator);
break;
default:
break;
}
}
}
}
return set;
}
}
POIがusermodel API *内の 'xlsx'ファイルを処理する方法は、ひどく非効率的です。 poi固有のコードで扱われる 'xls'とは異なり、' xlsx'ファイルは、あらゆるデータ項目をオブジェクトに膨らませて高価なDOMツリーをカプセル化するライブラリにいくつかの一般的なxmlで処理されます。コンテンツのみを反復したい場合は、POIのストリーミングAPIを参照してください。[このページ](https://poi.apache.org/spreadsheet/)の最後の表は、アプローチを比較しています。 – Holger
情報ありがとう!私はusermodelがそれが非効率的であるかもしれないと信じることができない - それはばかげている。私のxlsxファイルには、〜50,000行の38個の数値列+1(平均して)約20文字を含む文字列列があります。生データの面では、セルデータ自体は20MB未満のメモリを消費する必要があります。 Apache POIにこのような少量のデータをラップするには数GBのオーバーヘッドが必要になることは私にとってあまりにも奇妙に思えます。 – Coop