java - Apache POI 在尝试对中等大小的 XLSX 工作簿进行密码保护时抛出 OOM 错误 (~=80MB)
问题描述
使用 java 8 和 apache POI 和 POI-OOXML 3.14
这是我的方法:
private static void encryptXlsx(String inputPath, String outputPath, String password) throws IOException, InvalidFormatException, GeneralSecurityException {
//create a new workbook
Workbook wb = WorkbookFactory.create(new File(inputPath));
//Add password protection and encrypt the file
POIFSFileSystem fs = new POIFSFileSystem();
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
Encryptor enc = info.getEncryptor();
enc.confirmPassword(password); // s3cr3t is your password to open sheet.
OPCPackage opc = OPCPackage.open(new File(inputPath), PackageAccess.READ_WRITE);
OutputStream os = enc.getDataStream(fs);
opc.save(os);
opc.close();
FileOutputStream fos = new FileOutputStream(outputPath);
fs.writeFilesystem(fos);
fos.close();
}
错误堆栈是:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3044)
at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3065)
at org.apache.xmlbeans.impl.store.Locale$SaxHandler.startElement(Locale.java:3263)
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:4812)
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:3479)
at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1277)
at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1264)
at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:345)
at org.apache.poi.POIXMLTypeLoader.parse(POIXMLTypeLoader.java:92)
at org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument$Factory.parse(Unknown Source)
at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:173)
at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java:165)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.parseSheet(XSSFWorkbook.java:417)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java:382)
at org.apache.poi.POIXMLDocument.load(POIXMLDocument.java:178)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:249)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:293)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:252)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:231)
at XlsxEncryptExample.encryptXlsx(XlsxEncryptExample.java:36)
at XlsxEncryptExample.main(XlsxEncryptExample.java:28)
进程以退出代码 1 结束
如果有人能指出一种在不使用这么多内存的情况下读取此文件的方法,一个比 POI 或任何其他可能的解决方案更好地进行密码保护的库,我将不胜感激。
解决方案
据我了解,文档POI 通常会将整个电子表格读入内存。它确实说
请注意,usermodel 系统比低级 eventusermodel 具有更高的内存占用,但主要优点是使用起来更简单。另请注意,由于新的 XSSF 支持的 Excel 2007 OOXML (.xlsx) 文件是基于 XML 的,因此处理它们的内存占用高于旧的 HSSF 支持的 (.xls) 二进制文件。
它继续提供低内存占用的替代方案。
推荐阅读
- python - 贷款金额及贷款期限程序
- python - 根据其他行更新一行的列,Pandas
- hibernate - Hibernate JPA Spring Boot 忽略特定请求的 JSON 属性
- opengl - opengl中纹理单元和采样器制服之间的对应关系
- python - 提取href目标锚文本
- node.js - 如何在 aws lambda 上建立 nodejs 和 mongodb 之间的连接?
- python - Python中关于字典项添加的问题(猜词游戏)
- android - SMS Retriever API SMS Broadcaster 问题
- javascript - 使用 Array.map 并过滤对象数组,尝试删除包含 NaN 值的项目
- javascript - tmLanguage 中的注释行以 .* TextMate Grammar Syntax Highlight 开头