PDFbox 说 PDDocument 已关闭,但未关闭

2023-12-04

我正在尝试使用 PDFbox 填充重复的表单。我正在使用 TreeMap 并用单独的记录填充表单。 pdf 表单的格式是这样的:第一页列出六条记录,第二页插入一个静态页面。 (对于大于 6 个记录的 TreeMap,重复该过程)。我得到的错误特定于 TreeMap 的大小。我的问题就在于此。我不明白为什么当我用超过 35 个条目填充 TreeMap 时会收到此警告:

2018 年 4 月 23 日 2:36:25 AM org.apache.pdfbox.cos.COSDocument 最终确定 警告:警告:您没有关闭 PDF 文档

public class test {
    public static void main(String[] args) throws IOException,         IOException {
    // TODO Auto-generated method stub
    File dataFile = new File("dataFile.csv");
    File fi = new File("form.pdf");
    Scanner fileScanner = new Scanner(dataFile);
    fileScanner.nextLine();
    TreeMap<String, String[]> assetTable = new TreeMap<String, String[]>();
    int x = 0;
    while (x <= 36) {
        String lineIn = fileScanner.nextLine();
        String[] elements = lineIn.split(",");
        elements[0] = elements[0].toUpperCase().replaceAll(" ", "");
        String key = elements[0];
        key = key.replaceAll(" ", "");
        assetTable.put(key, elements);
        x++;
    }
    PDDocument newDoc = new PDDocument();
    int control = 1;
    PDDocument doc = PDDocument.load(fi);
    PDDocumentCatalog cat = doc.getDocumentCatalog();
    PDAcroForm form = cat.getAcroForm();
    for (String s : assetTable.keySet()) {
        if (control <= 6) {
            PDField IDno1 = (form.getField("IDno" + control));
            PDField Locno1 = (form.getField("locNo" + control));
            PDField serno1 = (form.getField("serNo" + control));
            PDField typeno1 = (form.getField("typeNo" + control));
            PDField maintno1 = (form.getField("maintNo" + control));
            String IDnoOne = assetTable.get(s)[1];
            //System.out.println(IDnoOne);
            IDno1.setValue(assetTable.get(s)[0]);
            IDno1.setReadOnly(true);
            Locno1.setValue(assetTable.get(s)[1]);
            Locno1.setReadOnly(true);
            serno1.setValue(assetTable.get(s)[2]);
            serno1.setReadOnly(true);
            typeno1.setValue(assetTable.get(s)[3]);
            typeno1.setReadOnly(true);
            String type = "";
            if (assetTable.get(s)[5].equals("1"))
                type += "Hydrotest";
            if (assetTable.get(s)[5].equals("6"))
                type += "6 Year Maintenance";
            String maint = assetTable.get(s)[4] + " - " + type;
            maintno1.setValue(maint);
            maintno1.setReadOnly(true);
            control++;
        } else {
            PDField dateIn = form.getField("dateIn");
            dateIn.setValue("1/2019 Yearlies");
            dateIn.setReadOnly(true);
            PDField tagDate = form.getField("tagDate");
            tagDate.setValue("2019 / 2020");
            tagDate.setReadOnly(true);
            newDoc.addPage(doc.getPage(0));
            newDoc.addPage(doc.getPage(1));
            control = 1;
            doc = PDDocument.load(fi);
            cat = doc.getDocumentCatalog();
            form = cat.getAcroForm();
        }
    }
    PDField dateIn = form.getField("dateIn");
    dateIn.setValue("1/2019 Yearlies");
    dateIn.setReadOnly(true);
    PDField tagDate = form.getField("tagDate");
    tagDate.setValue("2019 / 2020");
    tagDate.setReadOnly(true);
    newDoc.addPage(doc.getPage(0));
    newDoc.addPage(doc.getPage(1));
    newDoc.save("PDFtest.pdf");
    Desktop.getDesktop().open(new File("PDFtest.pdf"));

}

我一生都无法弄清楚我做错了什么。这是我使用 PDFbox 的第一周,所以我希望它能简单一些。

更新了错误消息

WARNING: Warning: You did not close a PDF Document
Exception in thread "main" java.io.IOException: COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?
    at org.apache.pdfbox.cos.COSStream.checkClosed(COSStream.java:77)
    at org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:125)
    at org.apache.pdfbox.pdfwriter.COSWriter.visitFromStream(COSWriter.java:1200)
    at org.apache.pdfbox.cos.COSStream.accept(COSStream.java:383)
    at org.apache.pdfbox.cos.COSObject.accept(COSObject.java:158)
    at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObject(COSWriter.java:522)
    at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObjects(COSWriter.java:460)
    at org.apache.pdfbox.pdfwriter.COSWriter.doWriteBody(COSWriter.java:444)
    at org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument(COSWriter.java:1096)
    at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:419)
    at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1367)
    at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1254)
    at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1232)
    at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1204)
    at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1192)
    at test.test.main(test.java:87)

警告本身

您似乎错误地理解了警告。它说:

警告:您没有关闭 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.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PDFbox 说 PDDocument 已关闭,但未关闭 的相关文章

随机推荐

  • 如何在Windows中的Visual Studio Code中创建tasks.json目录?

    我正在尝试编写一个任务 使用 Visual Studio Code 任务 在tasks json 中 为 Windows 用户创建一个目录 使用mkdir命令 运行良好除非该文件夹已存在 任务 json label release crea
  • Google Drive API 调用在 Fusiontables 上插入公共共享权限会导致内部错误

    我一直在尝试使用 Google Drive API 来使 Fusiontable 公开可读 但未能使其正常工作 我能够使用 OAuth 2 0 Playground 插入其他 Google Drive 文档的公共共享权限 但对于 Fusio
  • 如何在c#中执行多个oracle查询

    我正在尝试执行多个 Oracle 选择查询 如该帖子答案中所述here但我遇到了异常 如图所示 与oracle网站上解释的方式相同here 顺便说一句 是否有办法处理从这些查询之一找不到行的情况 string cmdstr begin op
  • R 中的“导入为”

    有没有办法在 R 中导入具有其他名称的包 就像您可能使用的那样import as在Python中 例如import numpy as np 我已经开始使用package function最近为了避免之间的冲突 比如说 Hmisc summa
  • 使用 ggplot2 绘制 xts 对象

    我想使用 ggplot2 绘制 xts 对象 但出现错误 这是我正在做的事情 dates lt c 2014 10 01 2014 11 01 2014 12 01 2015 01 01 2015 02 01 value lt as num
  • Android:按键盘上的“完成”按钮

    使用 appium 实现 Android 应用自动化 无法单击手机键盘上显示的 完成 按钮 有人可以帮助我们有什么方法可以使用 ADB Shell 命令单击 Android 手机完成按钮吗 在 Android 中 您无法直接单击键盘按键 除
  • C++ 从二进制文件中写入和读取双精度数

    我想对占用过多 RAM 的程序执行磁盘 I O 操作 我使用双精度矩阵 并认为将它们作为字节写入磁盘是最快的方法 我需要保留双精度 如何做到便携呢 我找到了这段代码 here 但作者说它不可移植 include
  • 将项目导入 Eclipse

    我有一个简单的问题如何将整个项目源导入 Eclipse 以便我可以轻松浏览它 具体来说 我已经下载了Maven源代码http maven apache org download html我只想像 Eclipse 中的其他项目一样查看它 我尝
  • JavaScript 中 [[prototype]] 属性的双括号有何意义?

    我知道每个 JavaScript 对象都有一个名为的内部属性 Prototype 一些实现允许通过名为的属性访问它 proto 而其他则不然 有什么特殊意义吗brackets该物业周围 它是一个 内部财产 对象的 来自ECMAScript
  • 双向链表——垃圾回收

    我创建了一个双向链表 我的列表仅包含 2 个元素 假设node1 and node2 并且我想删除head指向第一个节点的指针 node1 在列表中 因为在 Cpython 中 垃圾收集的主要算法是引用计数 现在我的问题是 示例1 如果我设
  • 如何定义自定义聚合函数来对向量列求和?

    我有一个两列的数据框 ID类型的Int and Vec类型的Vector org apache spark mllib linalg Vector DataFrame 如下所示 ID Vec 1 0 0 5 1 4 0 1 1 1 2 1
  • CSS3 替代 jQuery.fadeIn 和 fadeOut

    我编写了少量代码来尝试复制 jQuery fadeIn and fadeOut 使用 CSS 过渡的函数在触摸设备上看起来更好 理想情况下 我希望避免使用库 以便我可以准确地编写我想要的内容 并将其作为学习练习 fadeOut效果很好 的想
  • 是否有相当于“shopt -s nullglob”的 ZSH?

    我目前正在编写一个脚本 该脚本可以从我的桌面上删除所有 PNG 文件 我想创建一个文件路径数组 然后使用rm对每一个都发出命令 这是相关的代码 usr bin env bash shopt s nullglob files HOME Des
  • 搜索长字符串的 SQL 性能

    我需要将用户代理字符串存储在数据库中 以跟踪和比较不同浏览器之间的客户行为和销售业绩 一个非常简单的用户代理字符串大约有 100 个字符长 决定使用一个varchar 1024 用于在数据库中保存用户代理数据 我知道这有点矫枉过正 但这就是
  • 如何使用存储过程在 SQL Server 中透视表?

    原始输出 期望的输出 检查下面的示例供您参考 或者发布您当前的输出和所需的输出 SELECT INTO tblStock FROM SELECT A PartCode 10 StockQty WHs A Location UNION ALL
  • 使用vbs打开excel工作簿,运行宏并保存工作簿

    我有一个宏 需要每 5 分钟运行一次 我有一个vbs安排宏的文件 该宏正在检查某个文件夹中的新文件 将其信息写入表中 然后将文件移动到存档中 该表与宏位于同一个 Excel 文件中 它运行宏正常 但最后 它询问我是否要保存文件 我需要它来自
  • 使用多列的列表理解

    我有一个 pandas 数据框 其中有一列用于实际值和预测值 我想使用列表理解创建一个新列 当实际值 预测时 该列 1 否则为 0 我知道如何使用 np where 来做到这一点 但我很好奇如何使用列表理解来做到这一点 这可以使用np wh
  • 我可以在保存之前检查下载的图像是否损坏吗?

    在将下载的图像保存到我的文档目录之前 我可以检查它是否已损坏吗 如果是的话请告诉我怎么做 谢谢 UIImage im UIImage alloc initWithData YourNSData UIImageView imview test
  • 在 C# 中,有没有一种方法可以使用反射仅检索内置数据类型属性

    使用反射我想只检索内置数据类型来自 C 对象的属性 有没有比使用一堆更好的方法来做到这一点 或 在一个Where指定我感兴趣的类型的方法 Type sourceType typeof TSource var props sourceType
  • PDFbox 说 PDDocument 已关闭,但未关闭

    我正在尝试使用 PDFbox 填充重复的表单 我正在使用 TreeMap 并用单独的记录填充表单 pdf 表单的格式是这样的 第一页列出六条记录 第二页插入一个静态页面 对于大于 6 个记录的 TreeMap 重复该过程 我得到的错误特定于