PDF 合并大文件的 battle


目前在市面上流通的 java PDF 操作组件有 PDFboxitextPDF,当然商用的不在我们讨论的范围内。其实, itextPDF 也是有商用版本,但好像免费版本也适合大多场景使用,其次也没别的什么免费组件共选择与比对。

简介

itextPDF

itextPDF 属于半免费半商业的选择。在官网上也明确告知什么组件是免费开源的什么组件是闭源,供你按需方便的选择。在 itext 8 产品组下,

PDFBox

PDFBox 是 apache 开源项目,PDF 可操作的基本上都支持,也是市面上被追捧的项目,项目比较活跃。

💡 声明,仅站在大文件合并过程的场景上分享选择过程,与使用小心得。

合并代码、耗时及性能情况

itextPDF 8.0.5

long start = System.currentTimeMillis();
String mergedFilePath = "/Users/liull/Downloads/merge/itext8_" + index + ".pdf";
String mergeSourcePdfDir = "/Users/liull/Downloads/PDF文件";
File[] files = new File(mergeSourcePdfDir).listFiles();
List<File> pdfFiles = Arrays.stream(files).filter(file -> file.getName().endsWith("pdf")).collect(Collectors.toList());
int failedFileCount = 0;
try(OutputStream fileOut = new FileOutputStream(mergedFilePath)) {
    PdfDocument pdfWriterDoc = new PdfDocument(new PdfWriter(fileOut));
    for(File file: pdfFiles) {
        try(InputStream in = new FileInputStream(file)) {
            PdfDocument pdfReaderDoc = new PdfDocument(new PdfReader(in));
            int count = pdfReaderDoc.getNumberOfPages();
            try {
                pdfReaderDoc.copyPagesTo(1, count, pdfWriterDoc);
                pdfWriterDoc.flushCopiedObjects(pdfReaderDoc);
            } catch(Exception e) {
                failedFileCount++;
                System.out.println(file.getAbsolutePath());
                System.out.println(e.getMessage());
            } finally {
                pdfReaderDoc.close();
            }


        }
    }
    pdfWriterDoc.close();
}
long end = System.currentTimeMillis();
System.out.println("merge cost " + (end-start) + "ms, files:" + pdfFiles.size() + ", failed:" + failedFileCount);

机器资源,内存 4GB CPU 8核(mac)

材料量 并发量 耗时情况 是否 OOM
323 个材料
986.3 MB
1 12,139ms
323 个材料
986.3 MB
5 24,482ms
323 个材料
986.3 MB
10 52,162ms
323 个材料
986.3 MB
15

以下是单线程的 JVM 情况

以下是 10 并发的 JVM 情况

每个材料在 copy 完成后, 通过 pdfWriterDoc.flushCopiedObjects(pdfReaderDoc); 刷到硬盘上。

PDFBox 3.0.3

long start = System.currentTimeMillis();
String mergeSourcePdfDir = "/Users/liull/Downloads/PDF文件";
File[] files = new File(mergeSourcePdfDir).listFiles();
List<File> pdfFiles = Arrays.stream(files).filter(file -> file.getName().endsWith("pdf")).collect(Collectors.toList());
PDFMergerUtility pdfMergerUtility  = new PDFMergerUtility();
pdfMergerUtility.setAcroFormMergeMode(PDFMergerUtility.AcroFormMergeMode.PDFBOX_LEGACY_MODE);
pdfMergerUtility.setDocumentMergeMode(PDFMergerUtility.DocumentMergeMode.OPTIMIZE_RESOURCES_MODE);
pdfMergerUtility.setIgnoreAcroFormErrors(true);
pdfMergerUtility.setDestinationFileName("/Users/liull/Downloads/merge/PDFBox_" + index + ".pdf");
for (File file : pdfFiles) {
    pdfMergerUtility.addSource(new RandomAccessReadBufferedFile(file));
}
MemoryUsageSetting memoryUsageSetting = MemoryUsageSetting.setupMixed(1024*1024*256);
memoryUsageSetting.setTempDir(new File("/Users/liull/Downloads/merge/temp"));
//                    MemoryUsageSetting memoryUsageSetting = MemoryUsageSetting.setupTempFileOnly();
pdfMergerUtility.mergeDocuments(memoryUsageSetting.streamCache);
long end = System.currentTimeMillis();
System.out.println("merge cost " + (end-start) + "ms");

机器资源,内存 4GB CPU 8核(mac)

材料量 并发量 耗时情况 是否 OOM
323 个材料
986.3 MB
1 30,899ms
323 个材料
986.3 MB
5

以下是单线程的 JVM 情况

就性能比较结果而言,itext8 优秀于 PDFBox 的表现。


文章作者: beluga
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 beluga !
  目录