【发布时间】:2019-09-06 20:59:05
【问题描述】:
我正在使用 iText7 和 Java 来读取不是很大 (10-30MB) 的 PDF,但它们包含大量对象,在创建和使用 PdfDocument 时会导致 OutOfMemoryError 问题。 (内部xref 表和Map/Tree/Pdf[Dict/Array] 对象数以百万计。)
例如,一个 PDF 可能只有 33MB,但它包含一个包含 800 页的一百万行的单个表,而 PdfDocument 内部的簿记容量高达 400MB。这是示例代码和堆转储:
public static void main(String[] args) throws Exception {
// PDF file is 33MB on disk (one big table over 800 pages)
File pdf = new File("big.pdf"); // Also tried InputStream
PdfReader reader = new PdfReader(pdf); // 35MB heap
PdfDocument document = new PdfDocument(reader); // 400MB+ heap
// do stuff ... assuming we didn't get an OOM above
}
我们为 JVM 添加了更多内存,但我们不知道其中一些 PDF 可能有多大/复杂,因此需要一个长期的解决方案,理想情况下是让我们可以分段或在事件中读取内容的解决方案- 类回调方式(如 XML+STAX/SAX)。
有没有更有效的方法来流式传输 PDF 或将其分解为子 PdfDocuments 给定文件或 InputStream?我们想要定位和提取表单、表格、工具提示等对象。
更新:我与 IText 团队取得了联系,IText7 不允许部分阅读 PDF。因此,在这种情况下,除了添加更多 RAM 或预解析 PDF mysql 并查找“太多数据”(大量工作)之外,我无能为力。我还检查了PDFBox,它也遇到了同样的问题。
【问题讨论】:
-
我认为您将 PDF 拆分为最少页数,即 100 页或更适合您的页面,然后执行操作
-
@Vineet1982 - 我在考虑类似的策略,但后来又遇到了同样的问题:如何以编程方式拆分 PDF (
PdfSplitter) 我什至一开始都看不懂在没有内存问题的情况下进入 Java?问题是我不知道这些 PDF 来自哪里或它们的复杂性,所以我无法提前手动预拆分它们。 -
搜索互联网 有很多程序/代码可用于以编程方式拆分 pdf。拆分 PDF 不需要太多内存,它们是专门为此目的而精心创建的。有很多c程序可以用api调用,可以从java调用
-
也许:64 位 java 中的小对象指针曾经是 JVM 选项。数据修剪:无(嵌入)字体,图像最小化。一个(商业)PDF 优化器。 Linux。
-
正如我在更新中提到的,IText7 无法解决这个问题。如果在解析对象时有一个事件回调就好了,这样调用代码可以计算解析进度,如果数据太多可能会抛出异常。但是 API 非常封闭。我将继续评估其他解决方案和工具包。