我有一个包含三个字段private class TemplateImpl implements Template<ChildObject> {
public void doSomething(ChildObject object) { }
}
//and the factory:
private class Factory {
public Template<ChildObject> generate() {
return new TemplateImpl(); //TemplateImpl is a Template<ChildObject>
}
}
,txt_FirstName
和txt_MiddleName
的PDF文档,这些文档是使用 iTextSharp 写入的。
我有一个循环,用于创建输出文件,将其写入并关闭文件。
文件第一次在循环中写入名字和中间名。
文件第二次在循环中应使用名字,中间名并写上姓氏。
问题:问题是,当它第二次进入循环并将姓氏写为姓氏时,中间名消失了。
目标:我要做的主要事情是多次写入同一PDF文档
下载PDF模板: https://www.scribd.com/document/412586469/Testing-Doc
txt_LastName
答案 0 :(得分:5)
这似乎是一个简单的错误。第一次执行循环时,您将加载空白模板并输入名字和中间名。第二次循环,您再次加载空白模板,并向其中仅写入姓氏,然后保存为相同的文件名,并将其覆盖。如果在第二次循环中要加载已经包含名字和中间名的文件,则必须加载第一次编写的输出文件,而不是空白模板。或者,如果您想在if (counter == 2)
子句中再次加载空白模板,则必须写所有3个名称,而不仅仅是姓氏。
我复制了您的错误,并使其正常运行。这是我描述的第一个解决方案的代码(对代码进行了少量修改):
public static string templatePath = "C:\\temp\\template.pdf";
public static string OutputPath = "C:\\temp\\output\\";
private static void Fill_PDF()
{
string outputFile = "output.pdf";
int counter = 1;
for (int i = 0; i < 2; i++)
{
PdfStamper pdfStamper;
PdfReader reader = null;
/********** here's the changed part */
if (counter == 1)
{
reader = new PdfReader(File.ReadAllBytes(templatePath));
} else if (counter == 2)
{
reader = new PdfReader(File.ReadAllBytes(OutputPath + outputFile));
}
/************ end changed part */
PdfReader.unethicalreading = true;
if (File.Exists(OutputPath + outputFile))
{
pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
FileMode.Append, FileAccess.Write));
}
else
{
pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
FileMode.Create));
}
AcroFields pdfFormFields = pdfStamper.AcroFields;
if (counter == 1)
{
pdfFormFields.SetField("txt_FirstName", "Scooby");
pdfFormFields.SetField("txt_MiddleName", "Dooby");
counter++;
}
else if (counter == 2)
{
pdfFormFields.SetField("txt_LastName", "Doo");
}
pdfStamper.Close();
}
}
答案 1 :(得分:1)
代码有两个主要问题。 his answer中的@Nick已经指出了第一个:如果要在第二遍中编辑包含第一遍更改的文档版本,则必须将第一遍的输出文档作为的输入。第二遍,而不是原始模板。他还提供了解决此问题的代码。
第二期位于此处:
if (File.Exists(OutputPath + outputFile))
{
pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
FileMode.Append, FileAccess.Write));
}
else
{
pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
FileMode.Create));
}
如果输出文件已经存在,则将PdfStamper
的输出附加到该文件。错了! PdfStamper
的输出已经包含原始PDF的内容(来自PdfReader
),只要它们没有被更改。因此,您的代码有效地产生了第一遍的完整输出PDF和第二遍的完整输出PDF的串联。
PDF是一种二进制格式,这种格式的串联文件不会产生有效的PDF文件。因此,加载最终结果的PDF查看器将尝试修复这个双重PDF(假设它是单个PDF)。结果可能看起来不像您想要的。
要解决第二个问题,只需仅用if{...}else{...}
分支的内容替换上面的else
:
pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
FileMode.Create));
({FileMode.Create
被定义为
指定操作系统应创建一个新文件。如果文件已经存在,它将被覆盖。这需要
Write
权限。FileMode.Create
等同于请求如果文件不存在,请使用CreateNew
;否则,请使用Truncate
。如果该文件已经存在但为隐藏文件,则会抛出UnauthorizedAccessException
异常。
因此,如果已经有文件,它也会执行所需的操作。)
您可以通过运行几次Append
来识别代码中的问题,并观察输出文件的增长和增长。此外,如果您在Adobe Reader中打开该文件然后再次关闭,则Adobe Reader会保存更改。这些更改是维修工作。
您可能已经听说过PDF的增量更新,其中将更改附加到原始PDF。但这与单纯的级联不同,结果中的修订版是专门链接的,并且偏移量始终是从第一个修订版的开始而不是从当前修订版的开始计算的。此外,增量更新应该只包含 changed 对象。
iText包含一个带有4个参数的PdfStamper
构造函数,其中包括一个最终的布尔参数append
。使用该构造函数并将append
设置为true
可使iText创建增量更新。但是即使在这里,您也不会使用FileMode.Append
...
答案 2 :(得分:-1)
问题在于再次使用模板文件进行第二次迭代。
第一次迭代:按预期运行!
第二次迭代:您正在读取同一文件,并且仅写入姓氏。最后,将替换第一次迭代中创建的输出文件。
修复::知道该位置是否存在输出文件后,选择文件源,如下所示。这应该可以解决问题。亲自检查并成功!
if (File.Exists(OutputPath + outputFile))
{
reader = new PdfReader(File.ReadAllBytes(OutputPath + outputFile));
pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
FileMode.Append, FileAccess.Write));
}
else
{
reader = new PdfReader(File.ReadAllBytes(templatePath));
pdfStamper = new PdfStamper(reader, new FileStream(OutputPath + outputFile,
FileMode.Create));
}