gpt4 book ai didi

java - Apache POI SXSSFWorkbook 在 XLSX 文件内存问题中写入大约 500.000

转载 作者:行者123 更新时间:2023-12-04 20:23:43 26 4
gpt4 key购买 nike

我们使用 Spring Batch 和 Apache POI 开发了一个应用程序,用于从 DB(Oracle) 读取数据并将其写入 apache-poi 生成的 XLSX 文件中。
示例下方有一个读取器(从 DB ItemReader 读取数据)和写入器(ItemWriter)的作业:

@BeforeStep
public void beforeStep(StepExecution stepExecution) {
log.info("Calling analytic beforeStep");

cellProperties = new HashMap<String, Object>();
cellProperties.put(CellUtil.BORDER_LEFT, BorderStyle.THIN);
cellProperties.put(CellUtil.BORDER_RIGHT, BorderStyle.THIN);
cellProperties.put(CellUtil.BORDER_BOTTOM, BorderStyle.THIN);
cellProperties.put(CellUtil.BORDER_TOP, BorderStyle.THIN);

outputFilename = stepExecution.getJobExecution().getExecutionContext().getString("fileName");
File xlsxFile = new File(outputFilename);

if (xlsxFile.exists() && !xlsxFile.isDirectory()) {
log.info("ViewReportSalesAnalyticsExcelWriter File exist");
InputStream fileIn = null;
try {
fileIn = new BufferedInputStream(new FileInputStream(xlsxFile), 100);
workbook = new SXSSFWorkbook(new XSSFWorkbook(fileIn), 100);
} catch (Exception e) {
log.error("ViewReportSalesAnalyticsExcelWriter error: ", e);
} finally {
if (fileIn != null) {
try {
fileIn.close();
} catch (IOException e) {
log.error("ViewReportSalesAnalyticsExcelWriter error: ", e);
}
}
}
} else {
log.info("ViewReportSalesAnalyticsExcelWriter File not exist, creating");
workbook = new SXSSFWorkbook(100);
}

// temp files will be gzipped
workbook.setCompressTempFiles(true);
Sheet sheet = workbook.createSheet("Report POG - Analitico");
sheet.setFitToPage(true);
sheet.setDisplayGridlines(false);
sheet.setDefaultColumnWidth(23);
sheet.setDefaultRowHeight((short) 290);

addTitleToSheet(sheet);
//currRow++;
addHeaders(sheet);
//initDataStyle();
}

@Override
public void write(List<? extends ViewReportSalesAnalyticsDTO> items) throws Exception {
log.info("Analytic write, number of elements - {} ", items.size());

Sheet sheet = workbook.getSheetAt(1);
SimpleDateFormat spf = new SimpleDateFormat(PogEngineBatchConstants.DATE_FORMAT_REPORT);
Row row = null;

for (ViewReportSalesAnalyticsDTO data : items) {
int i = 0;
currRow++;

row = sheet.createRow(currRow);
createStringCell(row, data.getProductCode(), i++);
createStringCell(row, data.getProductDesc(), i++);
createStringCell(row, PogEngineBatchUtils.decodeFlagFactory(data.getFlagManufacturer()), i++);

for (String headerKey : dynamicHeaders) {
createStringCell(row, data.getSellingJson().get(headerKey) == null ? "OK" : //TODO always OK?
data.getSellingJson().get(headerKey), i++);
}
createStringCell(row, data.getMonitoringOutcome(), i++);

for (String headerKey : dynamicHeaders) {
createStringCell(row, data.getMonitorJson().get(headerKey) == null ? "OK" : //TODO always OK?
data.getMonitorJson().get(headerKey), i++);
}
}
}

@AfterStep
public void afterStep(StepExecution stepExecution) throws IOException {
FileOutputStream fos = new FileOutputStream(outputFilename);
log.info("ViewReportSalesAnalyticsExcelWriter afterStep, write records to file");
workbook.write(fos);
fos.close();
workbook.dispose();
workbook.close();
}
在 workbook.write(fos); 期间的 afterStep 中我们正在写大约 500.000 条记录,我们得到 GC 开销内存 .为了避免这个问题,我们将这个 VM 参数 -Xmx8192m 放在批处理启动器(sh)中,这需要很长时间,并且使用来自 VM(16 GB 和 8 CORE)的大量内存来结束进程并写入文件(约 110 MB)。
我们可以在代码中做些什么来不与内存重叠(因为数据会在 future 的执行中增长)?
为了不一次写入 500.000 条记录,有什么解决方案可以改变 workbook.write() 的行为?也许我们可以在这个过程中 split ?

最佳答案

该代码与 https://keyholesoftware.com/2012/11/12/generating-large-excel-files-using-spring-batch-part-three/ 非常相似.这种方法确实 不是 遵循 Spring Batch 提出的面向 block 的处理模型。问题是 Writer.write仅在内存中创建单元格,工作簿仅在 AfterStep 中写入磁盘打回来。显然,使用这种方法,所有项目都保存在内存中,直到整个步骤完成,然后才将它们写入磁盘。
项目应该在每个 block 之后而不是在整个步骤之后写入磁盘。

关于java - Apache POI SXSSFWorkbook 在 XLSX 文件内存问题中写入大约 500.000,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66052083/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com