警告本身
您似乎错误地理解了警告。它说:
警告:您没有关闭 PDF 文档
所以与你的想法相反,“PDFbox 说 PDDocument 已关闭,但实际上并未关闭”,PDFBox 说你做到了not关闭一个文档!
编辑后,人们会发现它实际上说的是COSStream
已关闭,并且possible cause是那个封闭的PDDocument
已经被关闭了。这只是一种可能!
您的情况的警告
也就是说,通过将一个文档中的页面添加到另一个文档中,您最终可能会引用两个文档中的这些页面。在这种情况下,在关闭两个文档的过程中(例如,通过垃圾收集自动),第二个关闭可能确实会偶然发现一些已经关闭的文档COSStream
实例。
所以我的第一个建议就是简单地do close最后的文件
doc.close();
newDoc.close();
可能不会删除警告,只是改变它们的时间。
实际上你不只是创建两个文档doc
and newDoc
,你甚至可以创建新的PDDocument
实例并将它们分配给doc
一次又一次,在此过程中将该变量中的前文档对象设置为可用于垃圾回收。因此,一旦不再被引用,您最终就会有一大堆文档需要关闭。
我认为关闭所有这些文档不是一个好主意doc
尽早,特别是在保存之前newDoc
.
但是,如果您的代码最终将作为较大应用程序的一部分运行,而不是作为小型一次性测试应用程序运行,那么您应该收集所有这些PDDocument
在某些情况下Collection
并在保存后立即明确关闭它们newDoc
然后清除集合。
实际上你的异常看起来像是丢失的异常之一PDDocument
实例已被垃圾收集关闭,因此即使使用简单的一次性实用程序,您也应该收集文档,以防止它们被 GC 处置。
(@Tilman,如果我错了,请纠正我......)
导入页面
为了防止不同文档共享页面出现问题,您可以尝试import将页面添加到目标文档,然后将导入的页面添加到目标文档页面树中。 IE。代替
newDoc.addPage(doc.getPage(0));
newDoc.addPage(doc.getPage(1));
by
newDoc.addPage(newDoc.importPage(doc.getPage(0)));
newDoc.addPage(newDoc.importPage(doc.getPage(1)));
这应该允许您关闭每个PDDocument
实例在doc
在失去它之前。
不过,这也有一定的缺点,参见。方法 JavaDoc 和这个答案在这里.
您的代码中的实际问题
在您的组合文档中,您将有许多具有相同名称的字段(至少在 CSV 文件中条目数量足够多的情况下),您最初将这些字段设置为不同的值。您可以从以下位置访问这些字段PDAcroForm
各自的原始文档,但不要将它们添加到PDAcroForm
合并结果文件。
这是自找麻烦! PDF 格式确实认为表单是文档范围的,所有字段都从文档的 AcroForm 字典引用(直接或间接),并且它期望具有相同名称的字段实际上是同一字段的不同可视化,因此都具有相同的值。
因此,PDF 处理器可能会以意想不到的方式处理您的文档字段,例如
- 通过在具有相同名称的所有字段中显示相同的值(因为它们应该具有相同的值)或
- 忽略您的字段(因为它们不在文档中AcroForm结构)。
特别是,以编程方式读取 PDF 字段值将会失败,因为在这种情况下,表单明确被认为是文档范围内的并且基于AcroForm。另一方面,PDF 查看器可能会首先显示您的设置值并使看起来一切正常。
为了防止这种情况,您应该在合并之前重命名字段。您可能会考虑使用PDFMergerUtility
它在幕后进行了这样的重命名。有关该实用程序类的示例用法,请查看PDFMergerExample
.