【问题标题】:How to merge two PDF files into one in Java?如何在Java中将两个PDF文件合并为一个?
【发布时间】:2011-04-04 20:39:46
【问题描述】:

我想使用PDFBox 将许多 PDF 文件合并为一个,这就是我所做的:

PDDocument document = new PDDocument();
for (String pdfFile: pdfFiles) {
    PDDocument part = PDDocument.load(pdfFile);
    List<PDPage> list = part.getDocumentCatalog().getAllPages();
    for (PDPage page: list) {
        document.addPage(page);
    }
    part.close();
}
document.save("merged.pdf");
document.close();

其中pdfFiles 是一个包含所有PDF 文件的ArrayList&lt;String&gt;

当我运行上述内容时,我总是得到:

org.apache.pdfbox.exceptions.COSVisitorException: Bad file descriptor

我做错了吗?还有其他方法吗?

【问题讨论】:

标签: java pdf pdfbox


【解决方案1】:

快速的 Google 搜索返回了这个错误:"Bad file descriptor while saving a document w. imported PDFs"

您似乎需要将要合并的 PDF 保持打开状态,直到您保存并关闭合并的 PDF。

【讨论】:

  • 虽然这个帖子已经有两年了,但这解决了问题。你必须让它们保持开放!
【解决方案2】:

为什么不用pdfbox的PDFMergerUtility呢?

PDFMergerUtility ut = new PDFMergerUtility();
ut.addSource(...);
ut.addSource(...);
ut.addSource(...);
ut.setDestinationFileName(...);
ut.mergeDocuments();

【讨论】:

  • 也可以,但我也使用 PDFBox 创建 PDF。
  • 它是否允许合并包含扫描图像的 PDF 和编写的 PDF?
  • @RageshKr:据我了解,无论其内容如何,​​它都会合并任何 PDF。
  • 有没有办法在每个页面中提到结果 pdf 的 page-no ??
  • pdf文件有密码可以用吗?
【解决方案3】:
package article14;

import java.io.File;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.util.PDFMergerUtility;

public class Pdf
{
    public static void main(String args[])
    {
        new Pdf().createNew();
        new Pdf().combine();
        }

    public void combine()
    {
        try
        {
        PDFMergerUtility mergePdf = new PDFMergerUtility();
        String folder ="pdf";
        File _folder = new File(folder);
        File[] filesInFolder;
        filesInFolder = _folder.listFiles();
        for (File string : filesInFolder)
        {
            mergePdf.addSource(string);    
        }
    mergePdf.setDestinationFileName("Combined.pdf");
    mergePdf.mergeDocuments();
        }
        catch(Exception e)
        {

        }  
    }

public void createNew()
{
    PDDocument document = null;
    try
    {
        String filename="test.pdf";
        document=new PDDocument();
        PDPage blankPage = new PDPage();
        document.addPage( blankPage );
        document.save( filename );
    }
    catch(Exception e)
    {

    }
}

}

【讨论】:

  • 吞下异常是一种不好的模式。捕获(异常 e){ }
【解决方案4】:

如果您想合并两个文件,其中一个文件覆盖另一个文件(例如:文档 A 是一个模板,而文档 B 有您要放置在模板上的文本),这可行:

创建“doc”后,您想在其上编写模板(templateFile)-

   PDDocument watermarkDoc = PDDocument.load(getServletContext()
                .getRealPath(templateFile));
   Overlay overlay = new Overlay();

   overlay.overlay(watermarkDoc, doc);

【讨论】:

    【解决方案5】:

    这是一个即用型代码,将四个 pdf 文件与来自 http://central.maven.org/maven2/com/itextpdf/itextpdf/5.5.0/itextpdf-5.5.0.jar 的 itext.jar 合并,更多内容请参见 http://tutorialspointexamples.com/

    import com.itextpdf.text.Document;
    import com.itextpdf.text.pdf.PdfContentByte;
    import com.itextpdf.text.pdf.PdfImportedPage;
    import com.itextpdf.text.pdf.PdfReader;
    import com.itextpdf.text.pdf.PdfWriter;
    
    /**
     * This class is used to merge two or more 
     * existing pdf file using iText jar.
     */
    public class PDFMerger {
    
    static void mergePdfFiles(List<InputStream> inputPdfList,
            OutputStream outputStream) throws Exception{
        //Create document and pdfReader objects.
        Document document = new Document();
        List<PdfReader> readers = 
                new ArrayList<PdfReader>();
        int totalPages = 0;
    
        //Create pdf Iterator object using inputPdfList.
        Iterator<InputStream> pdfIterator = 
                inputPdfList.iterator();
    
        // Create reader list for the input pdf files.
        while (pdfIterator.hasNext()) {
                InputStream pdf = pdfIterator.next();
                PdfReader pdfReader = new PdfReader(pdf);
                readers.add(pdfReader);
                totalPages = totalPages + pdfReader.getNumberOfPages();
        }
    
        // Create writer for the outputStream
        PdfWriter writer = PdfWriter.getInstance(document, outputStream);
    
        //Open document.
        document.open();
    
        //Contain the pdf data.
        PdfContentByte pageContentByte = writer.getDirectContent();
    
        PdfImportedPage pdfImportedPage;
        int currentPdfReaderPage = 1;
        Iterator<PdfReader> iteratorPDFReader = readers.iterator();
    
        // Iterate and process the reader list.
        while (iteratorPDFReader.hasNext()) {
                PdfReader pdfReader = iteratorPDFReader.next();
                //Create page and add content.
                while (currentPdfReaderPage <= pdfReader.getNumberOfPages()) {
                      document.newPage();
                      pdfImportedPage = writer.getImportedPage(
                              pdfReader,currentPdfReaderPage);
                      pageContentByte.addTemplate(pdfImportedPage, 0, 0);
                      currentPdfReaderPage++;
                }
                currentPdfReaderPage = 1;
        }
    
        //Close document and outputStream.
        outputStream.flush();
        document.close();
        outputStream.close();
    
        System.out.println("Pdf files merged successfully.");
    }
    
    public static void main(String args[]){
        try {
            //Prepare input pdf file list as list of input stream.
            List<InputStream> inputPdfList = new ArrayList<InputStream>();
            inputPdfList.add(new FileInputStream("..\\pdf\\pdf_1.pdf"));
            inputPdfList.add(new FileInputStream("..\\pdf\\pdf_2.pdf"));
            inputPdfList.add(new FileInputStream("..\\pdf\\pdf_3.pdf"));
            inputPdfList.add(new FileInputStream("..\\pdf\\pdf_4.pdf"));
    
    
            //Prepare output stream for merged pdf file.
            OutputStream outputStream = 
                    new FileOutputStream("..\\pdf\\MergeFile_1234.pdf");
    
            //call method to merge pdf files.
            mergePdfFiles(inputPdfList, outputStream);     
        } catch (Exception e) {
            e.printStackTrace();
        }
        }
    }
    

    【讨论】:

    • 这个问题显然被标记为pdfbox。您提出了itext 的解决方案。因此,您的答案是题外话。 (话虽如此,您的 iText 解决方案也是一个糟糕的解决方案,iText 开发人员通常会建议反对,因为它会放弃交互功能并忽略旋转和页面大小。)
    • 那么标题应该是“Java中如何用PdfBox将两个PDF文件合并为一个”
    • 此外,iText 带有一个令人讨厌的许可证。
    • 这个例子被命名为 IncorrectExample 因为这不是你通常用来解决旋转页面问题的方法,也不是合并文档的方法。正确的方法不是使用 Document / PdfWriter,而是使用 PdfStamper、PdfCopy 或 PdfSmartCopy。但是:在上述问题中,情况非常特殊,在这种情况下使用此示例是合理的:developers.itextpdf.com/examples/merging-pdf-documents-itext5/…
    【解决方案6】:

    使用 iText(以字节为单位的现有 PDF)

        public static byte[] mergePDF(List<byte[]> pdfFilesAsByteArray) throws DocumentException, IOException {
    
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        Document document = null;
        PdfCopy writer = null;
    
        for (byte[] pdfByteArray : pdfFilesAsByteArray) {
    
            try {
                PdfReader reader = new PdfReader(pdfByteArray);
                int numberOfPages = reader.getNumberOfPages();
    
                if (document == null) {
                    document = new Document(reader.getPageSizeWithRotation(1));
                    writer = new PdfCopy(document, outStream); // new
                    document.open();
                }
                PdfImportedPage page;
                for (int i = 0; i < numberOfPages;) {
                    ++i;
                    page = writer.getImportedPage(reader, i);
                    writer.addPage(page);
                }
            }
    
            catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
        document.close();
        outStream.close();
        return outStream.toByteArray();
    
    }
    

    【讨论】:

    • OP 很清楚地说 “我想使用 PDFBox 将许多 PDF 文件合并为一个”。 iText 不是 PDFBox。
    【解决方案7】:

    使用org.apache.pdfbox的多个pdf合并方法:

    public void mergePDFFiles(List<File> files,
                              String mergedFileName) {
        try {
            PDFMergerUtility pdfmerger = new PDFMergerUtility();
            for (File file : files) {
                PDDocument document = PDDocument.load(file);
                pdfmerger.setDestinationFileName(mergedFileName);
                pdfmerger.addSource(file);
                pdfmerger.mergeDocuments(MemoryUsageSetting.setupTempFileOnly());
                document.close();
            }
        } catch (IOException e) {
            logger.error("Error to merge files. Error: " + e.getMessage());
        }
    }
    

    在主程序中,使用文件列表和目标文件名调用 mergePDFFiles 方法。

            String mergedFileName = "Merged.pdf";
            mergePDFFiles(files, mergedFileName);
    

    调用mergePDFFiles后,加载合并文件

            File mergedFile = new File(mergedFileName);
    

    【讨论】:

    • 为什么要循环设置目标文件名?
    • 为什么要创建“文档”而不是循环使用它?
    猜你喜欢
    • 2014-11-16
    • 2015-02-06
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 2016-04-27
    • 2021-12-04
    • 1970-01-01
    相关资源
    最近更新 更多