大数据量Excel文件处理报错问题:【Tried to allocate an array of length XX, but the maximum length for this...】

一、背景描述

在上传大数据量的excel文档(.xlsx)时,报错:

Tried to allocate an array of length 260,008,239, but the maximum length for this record type is 100,000,000
if the file is not corrupt or large, please open an issue on bugzilla to request
increasing the maximum allowable size for this record type.
As a temporary workaround, consider setting a higher override value with lOUtils.setByteArrayMaxOverride()

缩小excel的大小,报错

<!DOCTYPEhtml><html> <head>
<title>Error</title> <style> body  width:
35em; margin: 0 auto; font-family: Tahoma
Verdana, Arial, sans-serif;} </style> </head>
<bodv> <h1>An error occurred.</h1>
<p>Sorry, the page you are looking for is
currently unavailable.<br/> Please try again
later.</p> <p>lf you are the system
administrator of this resource then you should
check the <a
href="http://nginx.org/r/error log">error
log</a> for details.</p> <p> <em>Faithfully
yours, nginx.</em></p> </body> </html>

二、报错原因和解决方案

1、Tried to allocate an array of length 260,008,239

报错代码:

MultipartFile file;
InputStream is = file.getInputStream();
// 这一行代码报错
Workbook wb = new XSSFWorkbook(is);

原因:

尝试分配一个长度为260,008,239的数组,但是该记录类型的最大长度为100,000,000所导致的。

解决方案1:

直接扩大允许的最大长度。

MultipartFile file;
InputStream is = file.getInputStream();
// 添加这行代码,根据你的报错给,比如我这里是260,008,239,那就比这个大
IOUtils.setByteArrayMaxOverride(300000000);
Workbook wb = new XSSFWorkbook(is);

解决方案2:

使用流

MultipartFile file;
InputStream is = file.getInputStream();
// 这个时候wb的类是StreamingWorkbook
Workbook wb = StreamingReader.builder()
	.rowCacheSize(100)
	.bufferSize(1024 * 4)
	.open(is);

2、Sorry, the page you are looking for is currently unavailable.

原因:

这是Nginx服务器的报错,是因为后端接口时间长时间没返回结果,服务器自动连接超时。

解决方案:

优化代码结构。

三、优化代码

项目上使用的 XSSFWorkbook 来处理 .xlsx文件。
需求:
将.xlsx 的每一个页签单独生成一个新的excel文件,并上传文件。
消耗内存和时间最长的:
将 原文件的每一个sheet页的值复制给新的 Workbook的sheet。
解决方案:
都使用流来进行。
具体步骤:
1、使用 StreamingWorkbook 来接收 原excel文件
2、使用 SXSSFWorkbook 来接收 原excel的每一个页签
代码:

MultipartFile file;
boolean excelFlag = ExcelUtils.isExcelFormat(fileParentName);
InputStream is = file.getInputStream();
try (Workbook wb = (excelFlag ? new HSSFWorkbook(is) :
        StreamingReader.builder().rowCacheSize(100).bufferSize(1024 * 4).open(is))) {
    int numberOfSheets = wb.getNumberOfSheets();
    for (int i = 0; i < numberOfSheets; i++) {
        Sheet sheet = wb.getSheetAt(i);
        // 设置sheet页名
        String sheetName = this.getsheetName();
        try (Workbook sheetWorkbook = new SXSSFWorkbook()) {
            Sheet newSheet = sheetWorkbook.createSheet(sheetName);
            this.copySheet(sheet, newSheet);
        }
    }
}
private void copySheet(Sheet sourceSheet, Sheet targetSheet) {
    sourceSheet.forEach(row -> {
        Row targetRow = targetSheet.createRow(row.getRowNum());
        // 使用默认高度
        targetSheet.getRow(row.getRowNum()).setHeight(targetSheet.getDefaultRowHeight());
        row.forEach(cell -> {
            targetRow.createCell(cell.getColumnIndex());
			// todo:进行格式转换会报错,这个后续需要修改
			// 是调用这个方法报错的,org.apache.poi.ss.usermodel.DataFormatter#isDate1904
            // String cellValue = new DataFormatter().formatCellValue(cell);
            targetRow.getCell(cell.getColumnIndex()).setCellValue(cell.getStringCellValue());
        });
    });
}

优化结果:
内存使用:几个G–>几百Mb
消耗时间:一百多秒 -->二三十秒

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值