当前位置: 首页 > 知识库问答 >
问题:

PDFbox表示PDDocument关闭时不关闭

元英朗
2023-03-14

我正在尝试用PDFBOX填充重复的表单。我正在使用树状图并用单个记录填充表单。pdf表格的格式是在第一页列出六个记录,在第二页插入一个静态页。(对于大于6条记录的树映射,该过程重复)。Im获得的错误与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)

共有1个答案

须敏学
2023-03-14

你似乎把警告弄错了。上面写着:

警告:您没有关闭PDF文档

因此,与您认为的“PDFBox说PDDocument关闭时它不关闭”相反,PDFBox说您没有关闭文档!

因此,我的第一个建议是,在文档的末尾用以下方式结束文档

doc.close();
newDoc.close();

很可能不会删除警告,只是更改它们的时间。

实际上,您不仅创建了两个文档docnewdoc,甚至还创建了新的pddocument实例,并一次又一次地将它们分配给doc,在将变量中的前一个文档对象设置为可进行垃圾回收的过程中。所以你最终会有一大堆文档在不再被引用时被关闭。

我认为提前关闭doc中的所有文档不是一个好主意,尤其是在保存newdoc之前。

但是,如果您的代码最终将作为一个较大的应用程序的一部分而不是作为一个小型一次性测试应用程序运行,那么您应该在某个集合中收集所有PDDocument实例,并在保存NewDoc后立即显式关闭它们,然后清除集合。

实际上,您的异常看起来像是丢失的pddocument实例中的一个已经被垃圾回收关闭了,因此即使使用了简单的一次性实用程序也应该收集文档,以防止它们被GC释放。

(@Tilman说错了请指正……)

为了防止不同文档共享页面时出现问题,您可以尝试将页面导入到目标文档中,然后将导入的页面添加到目标文档页面树中。即。替换

newDoc.addPage(doc.getPage(0));
newDoc.addPage(doc.getPage(1));

newDoc.addPage(newDoc.importPage(doc.getPage(0)));
newDoc.addPage(newDoc.importPage(doc.getPage(1)));

这是自找麻烦!PDF格式确实认为表单是文档范围内的,所有字段都(直接或间接)从文档的AcroForm字典中引用,并且它期望具有相同名称的字段实际上是同一字段的不同可视化,因此所有字段都具有相同的值。

因此,PDF处理器可能会以意想不到的方式处理文档字段,例如。

  • 通过在所有具有相同名称的字段中显示相同的值(因为预期这些字段具有相同的值)或
  • 忽略您的字段(因为它们不在文档AcroForm结构中)。

为了防止这种情况,您应该在合并之前重命名字段。您可以考虑使用pdfmergerutility,它在背后进行这样的重命名。有关该实用工具类的示例用法,请查看pdfmergerexample

 类似资料:
  • 我正在用Java生成一个PDDocument,代码如下... 然后保存并关闭文档,如下所示... 有没有一种方法可以关闭流并创建多个PDF,而不会出现抓取文件错误?

  • 我正在尝试加载PDF文档并打印它。整个过程都正常,但我收到了以下警告“警告:您没有关闭PDF文档”,我不明白为什么在我关闭文档后会出现这种情况。它出现在第11行(job.print();)。因为它是在打印时发生的,所以我无法调试它。

  • 当我试图用PDFBox读取PDF文件时,在PDDocument类上出现NoClassDefFound错误。以下是我得到的错误: 以下是生成错误的代码: 以下是我的进口商品,以防它们可能成为问题: 编辑:这是我用来从windows命令窗口运行程序的命令-

  • 我们从运行在云中的docker容器中的pdf生成器中获得间歇性异常。生成器的一部分处理获取SVG文档并将其加载到PDF中。每100ish调用它就会从importPageAsForm(tmpSVGPdf,0)引发以下异常。 我们还没能在本地复制这个问题。 然后我们打开一个PDF流&一个svg代码转换器的输出流。 当我们点击下面的importPageAsForm时,我们会传入临时SVG文档,在该函数中

  • 问题内容: 我想知道如果不手动关闭流,何时关闭。我的意思是,如果引用的范围不再存在,流将被关闭吗? 请考虑以下示例方案。 在这里,一旦完成流处理,我将退出,但是反过来将继续执行该程序的程序不会终止,而是继续进行其他操作。 我没有关闭溪流。一旦对A类的引用范围结束,它会自动关闭吗?(即何时结束)?GC会照顾吗?另外,我读到,一旦流程结束,流将关闭,并且系统释放为其他进程保留的所有资源。我们如何检查流

  • 我做了一个桌子预订系统,我想显示预订的桌子,使人们不能选择相同的桌子和相同的时间,但我不确定如何做到这一点。有些词是荷兰语的,随便问吧。 这是在表中显示信息的代码。