Java 使用更少的内存填充PDF表单,使用iText进行扁平化
我有一个web应用程序,它使用几个PDF表单创建多达500页的文档;每个表单一页,有40-50个字段。已完成的文档仅用于显示和打印,在创建文档时,不需要保留PDF表单的填写功能 我有使用iText 1.4.5的工作代码;它在不到30秒的时间内创建了这些文档(websphere,MVS),这对我来说很好 该应用程序确实占用了大量内存,并且最近导致了服务器崩溃。我感兴趣的是,我是否可以修改现有代码,以保留其大部分属性,并使用更少的内存。在我看来,这应该是可能的,因为使用的内存量表明整个文档在完成之前都在内存中,而我的逻辑不需要这样做——一旦一个页面被填满,我的程序就完成了,它就可以被写入磁盘,任何与该页面相关的内存都可以被释放 我找到了对com.lowagie.text.pdf.PdfWriter.freeReader()方法的引用,但不确定如何在我的环境中使用它。我的问题是,这是否会导致我的程序使用更少的内存(一次)以及将调用放在何处 我创建iText文档、PdfWriter和PdfReader对象,如下所示:Java 使用更少的内存填充PDF表单,使用iText进行扁平化,java,itext,Java,Itext,我有一个web应用程序,它使用几个PDF表单创建多达500页的文档;每个表单一页,有40-50个字段。已完成的文档仅用于显示和打印,在创建文档时,不需要保留PDF表单的填写功能 我有使用iText 1.4.5的工作代码;它在不到30秒的时间内创建了这些文档(websphere,MVS),这对我来说很好 该应用程序确实占用了大量内存,并且最近导致了服务器崩溃。我感兴趣的是,我是否可以修改现有代码,以保留其大部分属性,并使用更少的内存。在我看来,这应该是可能的,因为使用的内存量表明整个文档在完成之前
public PdfFormFiller(String givenInputSpecification,
Document givenDocument,
PdfWriter givenWriter)
{
// instance fields stored for PDF or tracking purposes.
inputSpecification = givenInputSpecification;
document = givenDocument;
writer = givenWriter;
contentByte = writer.getDirectContent();
// 'DirectContentUnder' is a contentByte object that allows
// our app to write out document content that appears
// underneath things written to the DirectContentOver; i.e.,
// this is a layer underneath some other things.
underContent = writer.getDirectContentUnder();
try
{
PdfReader reader = new PdfReader(inputSpecification);
template = writer.getImportedPage(reader, 1); // this line limits us to 1-page forms;
AcroFields aFields = reader.getAcroFields(); // the fields on the form.
<<more stuff in this constructor, deleted from here>>
我用以下公式向字段写入一个值:
/**
* * 'Fill' this given form with the given data values, i.e., write the given data
* values onto the positions in the forms corresponding to their field names.
* @param fieldValueMap a map with each key the name
* of the data field, and each value the string to be put on
* the form for that field.
*/
public void fillForm(Map fieldValueMap) throws DocumentException
{
Iterator keys = fieldValueMap.keySet().iterator();
while (keys.hasNext())
{
String fieldName = (String)keys.next();
FormField formField = (FormField)fields.get(fieldName);
String value = null;
if (fieldName != null)
{
value = (String)fieldValueMap.get(fieldName);
}
if (null != value && null != formField)
{
fillField(formField, value);
}
}
// add the template of the form; the fact that it is added
// to "underContent" causes iText to put it in a list if it's
// not already there, so it only gets added once per doc.
underContent.addTemplate(getTemplate(), 0, 0);
// start a new page - throws DocumentException
document.newPage();
}
/**
* fills the given field with the given value
* @param formField field and attributes
* @param value String value
*/
private void fillField(FormField formField, String value) throws DocumentException
{
if (formField.fieldType == AcroFields.FIELD_TYPE_CHECKBOX)
{
if (value.substring(0,1).equalsIgnoreCase("Y")) { value = "X"; }
else { value = " "; }
}
ColumnText columnText = new ColumnText(contentByte);
<<excised code determining fontToUse>>
setSimpleColumn(columnText, value, fontToUse, formField.box,
leading, Element.ALIGN_LEFT, false);
}
同样,主要的两个问题是:使用PdfWriter.freeReader()是否有助于释放在文档完成之前一直保留的内存,以及(2)在哪里调用它
如果有人想告诉我如何制作多页表单,我也很感兴趣…我没有看到在文档中循环的代码,但是当连接多个文档时,PdfWriter.freerereader()会释放内存。以下是javadoc的解释: 使用此方法将读取器写入文档并释放其使用的内存。主要用途是连接多个文档以将内存使用限制在当前附加文档中。 那你就是这么做的 听起来很简单,我认为您需要的是在循环处理过程中关闭每个文档,例如:
//loop iteration
// step 1
Document document = new Document();
// step 2
PdfWriter.getInstance(document, new FileOutputStream(filename));
// step 3
document.open();
// step 4
document.add(new Paragraph("Hello World!"));
//process the document.
...
//save the document.
...
// step 5
document.close();
//next loop iteration
既然您不需要保存每个文档,那么一次将20或30个表单合并为一个pdf,将其关闭,然后再创建20或30个表单是否可行,执行同样的操作,然后将最终文档与这些其他创建文档合并/合并,以避免将所有内容保留到最后?以下三个步骤对我有效:
- 释放作者占用的内存。请参考此链接
freemory()
方法
- 其次,您可以通过使用随机访问文件阵列读取pdf来节省内存
PdfReader pdfReader = new PdfReader(new RandomAccessFileOrArray(pdf), null);
- 最后,您可以
启动java的自动垃圾收集实用程序System.gc()
PdfReader pdfReader = new PdfReader(new RandomAccessFileOrArray(pdf), null);
PdfReader pdfReader = new PdfReader(pdf);