我的问题很简单。我想在App Engine中验证大小为50MB的文件是否格式正确。
这现在带来了许多大的挑战。首先是Apache XLS/XLSX POI API。当我将20MB的文件数据在本地加载到内存中进行验证时,它会抛出异常:
我需要打开和验证大小为20到25MB的电子表格。如果可能的话,50MB是一个不错的目标。我们要处理单个工作表上数十万行数据。
现在我的传统代码将整个文件加载到内存中,然后立即导致我的应用引擎实例崩溃。以下是我的传统代码:
现在,据说有基于事件的方法来处理每次遇到单元格时的动作监听器。但是虚拟代码 here 引用了:
我在调试器中检查了这个对象,并且它包含当前工作表中每个唯一字符串引用。这本质上正是我试图避免的。它会预先分配一大块内存来存储每个值。理想的解决方案需要获取输入字节流并在遍历文件时解码字符串,以减少内存占用。
因为字符串表肯定会占用大量内存空间。我正在处理15万到30万行项目电子表格。
现在快速指南提到您可以使用File或InputStream,如果使用File,则输入将被缓冲。问题在于,App Engine和Blob Store服务不知道File对象,而只返回InputStreams(据我所知)。
此外,另一个事件驱动模型 默认处理程序 在其接口定义的方法中似乎没有针对每个值的列或行概念(并且它还会预先分配整个共享字符串表)。
我已经没有更多想法了!我将尝试为此提供赏金。至少一个明确的“不可能”就足够了,然后我可以开始寻找解决方法,但我感觉我没有充分利用庞大的API。
这现在带来了许多大的挑战。首先是Apache XLS/XLSX POI API。当我将20MB的文件数据在本地加载到内存中进行验证时,它会抛出异常:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2271)
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:113)
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:140)
at org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource$FakeZipEntry.<init>(ZipInputStreamZipEntrySource.java:128)
at org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource.<init>(ZipInputStreamZipEntrySource.java:55)
at org.apache.poi.openxml4j.opc.ZipPackage.<init>(ZipPackage.java:84)
at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:272)
at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:79)
我需要打开和验证大小为20到25MB的电子表格。如果可能的话,50MB是一个不错的目标。我们要处理单个工作表上数十万行数据。
现在我的传统代码将整个文件加载到内存中,然后立即导致我的应用引擎实例崩溃。以下是我的传统代码:
public ErrorLog validateWorkbook(inputWorkbook)
{
int sheetCount = inputWorkbook.getNumberOfSheets();
for (int x = 0; x< sheetCount; x++)
{
Sheet currentSheet = inputWorkbook.getSheetAt(x);
Iterator<Row> rowIterator = currentSheet.rowIterator();
while(rowIterator.hasNext())
{
Iterator<Cell> cellIterator = rowIterator.next().cellIterator();
while(cellIterator.hasNext())
{
Cell currentCell = cellIterator.next();
boolean success = validateCellContents(currentCell);
if(!success)
ErrorLog.appendError(new Error()); // detailed user error explicitly defining error location, cell value, and recommended steps to fix
}
}
}
return ErrorLog;
}
现在,据说有基于事件的方法来处理每次遇到单元格时的动作监听器。但是虚拟代码 here 引用了:
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(container);
我在调试器中检查了这个对象,并且它包含当前工作表中每个唯一字符串引用。这本质上正是我试图避免的。它会预先分配一大块内存来存储每个值。理想的解决方案需要获取输入字节流并在遍历文件时解码字符串,以减少内存占用。
因为字符串表肯定会占用大量内存空间。我正在处理15万到30万行项目电子表格。
现在快速指南提到您可以使用File或InputStream,如果使用File,则输入将被缓冲。问题在于,App Engine和Blob Store服务不知道File对象,而只返回InputStreams(据我所知)。
此外,另一个事件驱动模型 默认处理程序 在其接口定义的方法中似乎没有针对每个值的列或行概念(并且它还会预先分配整个共享字符串表)。
我已经没有更多想法了!我将尝试为此提供赏金。至少一个明确的“不可能”就足够了,然后我可以开始寻找解决方法,但我感觉我没有充分利用庞大的API。