11

我正在使用XSSFapache-POI读取 XLSX 文件。我遇到了一个错误java.lang.OutOfMemoryError: Java heap space。后来,增加了-Xmx1024m用于java类的堆大小仍然重复相同的错误。

代码:

String filename = "D:\\filename.xlsx";
FileInputStream fis = null;
try {
   fis = new FileInputStream(filename);
   XSSFWorkbook workbook = new XSSFWorkbook(fis);

在上面的代码段中,执行停止XSSFWorkbook并抛出指定的错误。有人可以建议更好的方法来读取大型 XLSX 文件。

4

2 回答 2

17

POI 允许您以流式方式读取 excel 文件。API 几乎是 SAX 的包装器。确保使用接受字符串的构造函数以正确的方式打开 OPC 包。否则你可能会立即耗尽内存。

OPCPackage pkg = OPCPackage.open(file.getPath());
XSSFReader reader = new XSSFReader(pkg);

现在,阅读器将允许您获取InputStreams不同的部分。如果您想自己进行 XML 解析(使用 SAX 或 StAX),您可以使用这些。但这需要非常熟悉格式。

一个更简单的选择是使用XSSFSheetXMLHandler。这是读取第一张纸的示例:

StylesTable styles = reader.getStylesTable();
ReadOnlySharedStringsTable sharedStrings = new ReadOnlySharedStringsTable(pkg);
ContentHandler handler = new XSSFSheetXMLHandler(styles, sharedStrings, mySheetContentsHandler, true);

XMLReader parser = XMLReaderFactory.createXMLReader();
parser.setContentHandler(handler);
parser.parse(new InputSource(reader.getSheetsData().next()));

其中 mySheetsContentHandler 应该是您自己的XSSFSheetXMLHandler.SheetContentsHandler实现。这个类将被提供行和单元格。

但是请注意,如果您的共享字符串表很大(如果您的大表中没有任何重复的字符串,则会发生这种情况),这可能会适度消耗内存。如果内存仍然是个问题,我建议使用原始 XML 流(也由 XSSFReader 提供)。

于 2012-07-05T13:56:23.213 回答
0

为了补充@waxwing 的答案,如果输入 XLS(X) 文件受密码保护,您将需要通过使用解密装饰器包装原始文件来获取纯输入流。但首先,您需要将文件作为POIFSFileSystem.

简而言之:

String pass = "secret";
File file = new File("data/1.xlsx");
    
try (POIFSFileSystem fs = new POIFSFileSystem(file);
   // wrap in org.apache.poi.poifs.filesystem.DocumentFactoryHelper.getDecryptedStream
   InputStream in = DocumentFactoryHelper.getDecryptedStream(fs, pass);
   OPCPackage pkg = OPCPackage.open(in)) 
{
    XSSFReader reader = new XSSFReader(pkg);
        
    StylesTable styles = reader.getStylesTable();
    ReadOnlySharedStringsTable sharedStrings = new ReadOnlySharedStringsTable(pkg);
    SheetContentsHandler f = new SheetContentsHandler() {
       // ... your implementation of SheetContentsHandler interface ...
    };
    ContentHandler handler = new XSSFSheetXMLHandler(styles, sharedStrings, f, true);
    XMLReader parser = XMLReaderFactory.createXMLReader();
    parser.setContentHandler(handler);
    parser.parse(new InputSource(reader.getSheetsData().next()));
}
于 2021-05-24T10:36:13.207 回答