以下代码合并pdf文件并返回合并的pdf数据。当这段代码运行时,我尝试将100个文件与大约500kb的每个文件组合在一起,我在行document.close();中得到了outofmemory错误。这个代码在web环境中运行,是webspehere服务器可用的内存有问题吗?我在一篇文章中读到了使用freeReader方法,但我无法理解如何使用它我的方案。
protected ByteArrayOutputStream joinPDFs(List<InputStream> pdfStreams,
boolean paginate) {
Document document = new Document();
ByteArrayOutputStream mergedPdfStream = new ByteArrayOutputStream();
try {
//List<InputStream> pdfs = pdfStreams;
List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPages = 0;
//Iterator<InputStream> iteratorPDFs = pdfs.iterator();
Iterator<InputStream> iteratorPDFs = pdfStreams.iterator();
// Create Readers for the pdfs.
while (iteratorPDFs.hasNext()) {
InputStream pdf = iteratorPDFs.next();
if (pdf == null)
continue;
PdfReader pdfReader = new PdfReader(pdf);
readers.add(pdfReader);
totalPages += pdfReader.getNumberOfPages();
}
//clear this
pdfStreams = null;
//WeakReference ref = new WeakReference(pdfs);
//ref.clear();
// Create a writer for the outputstream
PdfWriter writer = PdfWriter.getInstance(document, mergedPdfStream);
writer.setFullCompression();
document.open();
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA,
BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF
// data
PdfImportedPage page;
int currentPageNumber = 0;
int pageOfCurrentReaderPDF = 0;
Iterator<PdfReader> iteratorPDFReader = readers.iterator();
// Loop through the PDF files and add to the output.
while (iteratorPDFReader.hasNext()) {
PdfReader pdfReader = iteratorPDFReader.next();
// Create a new page in the target for each source page.
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
pageOfCurrentReaderPDF++;
document.setPageSize(pdfReader
.getPageSizeWithRotation(pageOfCurrentReaderPDF));
document.newPage();
// pageOfCurrentReaderPDF++;
currentPageNumber++;
page = writer.getImportedPage(pdfReader,
pageOfCurrentReaderPDF);
cb.addTemplate(page, 0, 0);
// Code for pagination.
if (paginate) {
cb.beginText();
cb.setFontAndSize(bf, 9);
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, ""
+ currentPageNumber + " of " + totalPages, 520,
5, 0);
cb.endText();
}
}
pageOfCurrentReaderPDF = 0;
System.out.println("now the size is: "+pdfReader.getFileLength());
}
mergedPdfStream.flush();
document.close();
mergedPdfStream.close();
return mergedPdfStream;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen())
document.close();
try {
if (mergedPdfStream != null)
mergedPdfStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return mergedPdfStream;
}
由于 V
答案 0 :(得分:3)
此代码将所有PDF合并到内存(堆中)的数组中,因此,内存使用量将随着合并的文件数量线性增长。
我不知道freeReader方法,但也许您可以尝试将合并的PDF写入临时文件而不是字节数组? mergedPdfStream
将是FileOutputStream
而不是ByteArrayOutputStream
。然后你回来,例如File
对客户端代码的引用。
或者你可以增加Java可以使用的内存量(-Xmx
JVM参数),但如果要合并的文件数量最终增加,你会发现自己遇到同样的问题。
答案 1 :(得分:1)
这不是执行文件操作的正确方法。您正在使用内存中的ArrayList
和Array
合并文件。您应该使用文件IO和缓冲技术。
您是否希望最后显示最终合并文件?然后,您可以在完成所有合并后打开文件。
byte[]
我的意思) Java在启动时分配的内存有限,因此一次合并大量文件会导致应用程序崩溃。您应该使用ThreadPool
在单独的线程中尝试此合并操作,以便您的应用程序不会因此而受到限制。
感谢。
答案 2 :(得分:0)
100个文件* 500 kB约为50 MB。如果最大堆大小为64 MB,我很确定此代码在这种情况下不起作用。
答案 3 :(得分:0)
首先,为什么要将所有Iterator&lt;&gt;的代码混乱?样板代码?
你听说过for
陈述吗?
即
for (PDfReader pdfReader: readers) {
// code for each single PDF reader in readers
}
第二:考虑在完成后立即关闭pdfReader。这将有希望刷新一些缓冲区并释放原始PDF占用的内存。