尝试使用iText生成可变页面PDF时出现异常

时间:2013-05-10 22:01:54

标签: java pdf pdf-generation itext

我正在尝试创建政府工资表单的自动填写PDF,其中涉及可变页数的可能性。我目前正在将每个页面存储为Map,其中键是字段的名称,值是其内容。 目前,我有这段代码:

in = new FileInputStream(inputPDF);
PdfCopyFields adder = new PdfCopyFields(outStream);
PdfReader reader = null;
PdfStamper stamper = null;
ByteArrayOutputStream baos = null;
for (int pageNum = 0; pageNum < numPages; pageNum++) {
    reader = new PdfReader(in);
    baos = new ByteArrayOutputStream();
    stamper = new PdfStamper(reader, baos);
    AcroFields form = stamper.getAcroFields();
    Map<String, String> page = pages.get(pageNum);
    setFieldsToPage(form, pageNum);
    populatePage(form, page, pageNum);
    stamper.close();
    reader = new PdfReader(baos.toByteArray());
    adder.addDocument(reader);
}

调用的方法是:

private void populatePage(AcroFields form, Map<String, String> pageMap, int pageNum) throws Exception {
    ArrayList<String> fieldNames = new ArrayList<String>();
    for (String key : pageMap.keySet()) {
        fieldNames.add(key);
    }
    for (String key : fieldNames) {
        form.setField(key + pageNum, pageMap.get(key));
    }
}

private void setFieldsToPage(AcroFields form, int pageNum) {
    ArrayList<String> fieldNames = new ArrayList<String>();
    Map<String, AcroFields.Item> fields = form.getFields();
    for (String fieldName : fields.keySet()) {
        fieldNames.add(fieldName);
    }
    for (String fieldName : fieldNames) {
        form.renameField(fieldName, fieldName + pageNum);
    }
}

问题是这会在循环的第二次迭代中抛出异常:在reader = new PdfReader(in);我得到以下异常: java.io.IOException: PDF header signature not found. 我在这里做错了什么,我该如何解决?

编辑: 这是一个例外:

java.io.IOException: PDF header signature not found.
  at com.lowagie.text.pdf.PRTokeniser.checkPdfHeader(Unknown Source)
  at com.lowagie.text.pdf.PdfReader.readPdf(Unknown Source)
  at com.lowagie.text.pdf.PdfReader.<init>(Unknown Source)
  at com.lowagie.text.pdf.PdfReader.<init>(Unknown Source)

顺便说一下,如果格式化不好,我很抱歉 - 这是我第一次使用stackoverflow。

2 个答案:

答案 0 :(得分:2)

你的问题是你在第一次使用它之后已经多次尝试读取相同的输入流:

in = new FileInputStream(inputPDF);
[...]
for (int pageNum = 0; pageNum < numPages; pageNum++) {
    reader = new PdfReader(in);
    [...]
}

在第一次迭代中读取整个流;因此,在第二个new PdfReader(in)基本上尝试解析导致您的

的空文件
  

java.io.IOException:找不到PDF标题签名

您可以通过每次直接使用输入文件路径构建PdfReader来解决这个问题:

for (int pageNum = 0; pageNum < numPages; pageNum++) {
    reader = new PdfReader(inputPDF);
    [...]
}

但还有两件事:

  • 使用后,您不会关闭PdfReader个实例。在最新的iText版本中,由于它与众多用例相冲突,因此隐式关闭读取器已从代码中删除。因此,在您使用读卡器完成工作后(这包括使用该读卡器的任何压模等也已关闭),您应该明确关闭读卡器。

  • 一般情况下,如果您的文件系统中已经有PDF,那么通过FileInputStream为它打开PdfReader是非常浪费资源的 - 读取器首先完全用输入流初始化将该流读入内存(byte []),然后解析内存中的表示;用文件路径初始化的阅读器直接解析光盘表示。

答案 1 :(得分:0)

例外情况告诉您,您正在阅读的文件不以%PDF-开头。

写一个不涉及iText的小例子并检查InputStream in的前5个字节,你会发现你做错了什么(除非你告诉我们,否则我们无法告诉你5个字节)。