如何读取大小> 40MB的XLSX文件

时间:2012-07-05 13:16:55

标签: java out-of-memory xlsx

我正在使用XSSF apache-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文件。

2 个答案:

答案 0 :(得分:15)

POI允许您以流方式读取Excel文件。 API几乎是SAX的包装器。确保使用带有String的构造函数以正确的方式打开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提供)。

答案 1 :(得分: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()));
}