如何使用 Node.js 将 PDF 文件合并为一个 PDF 文件

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronPDF让您在Node.js中仅需几行代码即可将多个PDF文件合并为一个文档。 使用toFile()保存结果。

快速入门:合并PDF文件

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/quickstart-merge.js
// Install: npm install ironpdf
const IronPdf = require('ironpdf');

async function quickMerge() {
  const docs = await Promise.all([
    IronPdf.PdfDocument.fromFile('doc1.pdf'),
    IronPdf.PdfDocument.fromFile('doc2.pdf'),
    IronPdf.PdfDocument.fromFile('doc3.pdf'),
  ]);
  const merged = await IronPdf.PdfDocument.merge(docs);
  await merged.toFile('merged-output.pdf');
}

quickMerge();
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/quickstart-merge.js
// Install: npm install ironpdf
const IronPdf = require('ironpdf');

async function quickMerge() {
  const docs = await Promise.all([
    IronPdf.PdfDocument.fromFile('doc1.pdf'),
    IronPdf.PdfDocument.fromFile('doc2.pdf'),
    IronPdf.PdfDocument.fromFile('doc3.pdf'),
  ]);
  const merged = await IronPdf.PdfDocument.merge(docs);
  await merged.toFile('merged-output.pdf');
}

quickMerge();
JAVASCRIPT

IronPDF是Node.js的PDF操作库,处理HTML到PDF转换、文档组装和PDF修改,而无需任何系统级的PDF工具。 在合并文档时,它保留每个源文件中的字体、图像、嵌入式表单和页面几何。

在部署到生产环境之前,请配置您的IronPDF许可证密钥以去除试用水印并启用完整输出。 要为您的操作系统设置渲染引擎,请遵循IronPdfEngine配置指南


在Node.js中如何合并多个PDF文件?

PdfDocument对象的数组并返回一个新文档,其中包含按源文档在数组中的顺序排列的每一页。 该操作是非破坏性的;原始文件对象不会被修改。

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-pdfs.js
const IronPdf = require('ironpdf');

async function mergePdfs(outputFilePath, inputFiles) {
  // Load all source documents in parallel
  const pdfDocs = await Promise.all(
    inputFiles.map(file => IronPdf.PdfDocument.fromFile(file))
  );

  // Combine into one document, preserving page order
  const mergedPdf = await IronPdf.PdfDocument.merge(pdfDocs);

  // Write the result to disk
  await mergedPdf.toFile(outputFilePath);
  console.log(`Merged PDF saved to ${outputFilePath}`);
}

(async () => {
  const inputFiles = ['report-jan.pdf', 'report-feb.pdf', 'report-mar.pdf'];
  await mergePdfs('quarterly-report.pdf', inputFiles);
})();
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-pdfs.js
const IronPdf = require('ironpdf');

async function mergePdfs(outputFilePath, inputFiles) {
  // Load all source documents in parallel
  const pdfDocs = await Promise.all(
    inputFiles.map(file => IronPdf.PdfDocument.fromFile(file))
  );

  // Combine into one document, preserving page order
  const mergedPdf = await IronPdf.PdfDocument.merge(pdfDocs);

  // Write the result to disk
  await mergedPdf.toFile(outputFilePath);
  console.log(`Merged PDF saved to ${outputFilePath}`);
}

(async () => {
  const inputFiles = ['report-jan.pdf', 'report-feb.pdf', 'report-mar.pdf'];
  await mergePdfs('quarterly-report.pdf', inputFiles);
})();
JAVASCRIPT

Promise.all()并行加载源文件,而不是一次加载一个,这在处理更大的集合时很重要。 merge()调用按数组顺序连接文档,因此请按希望它们在输出中出现的顺序将文件放入数组中。

提示传递文件路径为绝对路径或相对Node.js进程工作目录的路径。 fromFile()方法不解决相对于脚本文件本身的路径。

代码的每个部分是做什么的?

  • PdfDocument.fromFile(): 从磁盘读取PDF并返回PdfDocument对象。 完整方法签名请参阅IronPDF for Node.js API参考
  • Promise.all():同时调度所有文件加载操作,减少多文档合并的总加载时间。 此模式也适合多线程和并发PDF生成场景。
  • PdfDocument,保留每个来源的所有格式、图像和嵌入内容。
  • toFile():将合并的文档写入指定路径。 将其与PDF压缩结合使用,以在需要时减少输出文件大小。

如何合并每个PDF的特定页面?

传递每个源文档的每一页并不总是目的。 要从每个输入文件合并选择的页面范围,请在将文档传递给merge()之前提取所需的页面。

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-specific-pages.js
const IronPdf = require('ironpdf');

// Each entry specifies a file and the range of pages to include (zero-indexed)
const pageRanges = [
  { file: 'contract.pdf',  startPage: 0, endPage: 2 },
  { file: 'appendix.pdf',  startPage: 0, endPage: 0 },
  { file: 'signature.pdf', startPage: 0, endPage: 0 },
];

async function mergeSpecificPages(outputFile, ranges) {
  const pdfsToMerge = [];

  for (const range of ranges) {
    const pdf = await IronPdf.PdfDocument.fromFile(range.file);
    // extractPages returns a new PdfDocument with only the specified page range
    const pages = pdf.extractPages(range.startPage, range.endPage);
    pdfsToMerge.push(pages);
  }

  const merged = await IronPdf.PdfDocument.merge(pdfsToMerge);
  await merged.toFile(outputFile);
}

mergeSpecificPages('assembled-contract.pdf', pageRanges);
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-specific-pages.js
const IronPdf = require('ironpdf');

// Each entry specifies a file and the range of pages to include (zero-indexed)
const pageRanges = [
  { file: 'contract.pdf',  startPage: 0, endPage: 2 },
  { file: 'appendix.pdf',  startPage: 0, endPage: 0 },
  { file: 'signature.pdf', startPage: 0, endPage: 0 },
];

async function mergeSpecificPages(outputFile, ranges) {
  const pdfsToMerge = [];

  for (const range of ranges) {
    const pdf = await IronPdf.PdfDocument.fromFile(range.file);
    // extractPages returns a new PdfDocument with only the specified page range
    const pages = pdf.extractPages(range.startPage, range.endPage);
    pdfsToMerge.push(pages);
  }

  const merged = await IronPdf.PdfDocument.merge(pdfsToMerge);
  await merged.toFile(outputFile);
}

mergeSpecificPages('assembled-contract.pdf', pageRanges);
JAVASCRIPT

extractPages(startPage, endPage)接受从零开始的页面索引。 传递0, 2提取前三页。 循环按其在merge()将它们连接成最终输出。

该模式在从签名页、附录和保存在单独文件中的封面组装合同时很有用。 您可以从每个源中准确收集重要的页面,而不会在磁盘上重复文件。

请注意IronPDF中的页面索引是从零开始的。 文档的第1页是索引0,第2页是索引1,依此类推。)]}


Icon Quote related to 如何合并每个PDF的特定页面?

我最喜欢的这种库是 IronPDF。它允许快速高效地操作 PDF 文件。它还具有许多有价值的功能,比如导出为 PDF/A 格式和数字签名 PDF 文档。

Milan Jovanovic related to 如何合并每个PDF的特定页面?

Milan Jovanovic

微软MVP

查看案例研究
Icon Quote related to 如何合并每个PDF的特定页面?

IronOCR 意味着我们每年可以节省 $40,000 的人工处理成本,同时提高生产力,并释放资源用于高影响任务。我强烈推荐它。

Brent Matzelle related to 如何合并每个PDF的特定页面?

Brent Matzelle

首席技术官,OPYN

查看案例研究
Icon Quote related to 如何合并每个PDF的特定页面?

Iron Suite 在我们的运营中起着至关重要的作用。这些工具提高了业务各方面的效率,包括创建平面图和改善库存管理。

David Jones related to 如何合并每个PDF的特定页面?

David Jones

首席软件工程师,Agorus Build

查看案例研究

如何向合并后的PDF添加页眉和页脚?

合并后,在结果文档上调用addHtmlFooter(),以在所有页面上应用一致的页眉和页脚。 这些方法接受HTML字符串和一个选项对象。

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-headers-footers.js
const IronPdf = require('ironpdf');

async function mergeWithHeadersFooters(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Apply a styled header to every page
  await mergedPdf.addHtmlHeader('<h3 style="color:#333;">Quarterly Report</h3>', {
    height: 25,
    drawDividerLine: true,
  });

  // Apply a page-numbering footer
  await mergedPdf.addHtmlFooter('<p style="font-size:10px;">Page {page} of {total-pages}</p>', {
    height: 20,
    drawDividerLine: true,
  });

  await mergedPdf.toFile(outputFile);
}

mergeWithHeadersFooters(['q1.pdf', 'q2.pdf', 'q3.pdf'], 'annual-report.pdf');
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-headers-footers.js
const IronPdf = require('ironpdf');

async function mergeWithHeadersFooters(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Apply a styled header to every page
  await mergedPdf.addHtmlHeader('<h3 style="color:#333;">Quarterly Report</h3>', {
    height: 25,
    drawDividerLine: true,
  });

  // Apply a page-numbering footer
  await mergedPdf.addHtmlFooter('<p style="font-size:10px;">Page {page} of {total-pages}</p>', {
    height: 20,
    drawDividerLine: true,
  });

  await mergedPdf.toFile(outputFile);
}

mergeWithHeadersFooters(['q1.pdf', 'q2.pdf', 'q3.pdf'], 'annual-report.pdf');
JAVASCRIPT

{total-pages}占位符在渲染时根据合并文档的页面计数进行解析。 使用drawDividerLine: true在页眉或页脚与页面内容之间进行视觉分隔。

在合并后应用页眉和页脚意味着合并文档中的每一页都得到相同的处理,无论它来自哪个源文件。 欲了解完整的页眉和页脚配置选项,请参阅HTML页眉和页脚示例


如何用密码保护合并后的PDF?

合并后通过调用saveAs()并提供安全选项对象来应用密码保护和权限限制。 这可以防止对合并文档的未经授权访问。

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-security.js
const IronPdf = require('ironpdf');

async function mergeWithSecurity(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Restrict the merged document to print-only access
  await mergedPdf.saveAs(outputFile, {
    userPassword: 'viewerpass',
    ownerPassword: 'adminpass',
    allowUserAnnotations: false,
    allowUserCopyPasteContent: false,
    allowUserFormData: false,
    allowUserPrinting: true,
  });
}

mergeWithSecurity(['invoice-1.pdf', 'invoice-2.pdf'], 'secured-invoices.pdf');
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-security.js
const IronPdf = require('ironpdf');

async function mergeWithSecurity(inputFiles, outputFile) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Restrict the merged document to print-only access
  await mergedPdf.saveAs(outputFile, {
    userPassword: 'viewerpass',
    ownerPassword: 'adminpass',
    allowUserAnnotations: false,
    allowUserCopyPasteContent: false,
    allowUserFormData: false,
    allowUserPrinting: true,
  });
}

mergeWithSecurity(['invoice-1.pdf', 'invoice-2.pdf'], 'secured-invoices.pdf');
JAVASCRIPT

userPassword是打开文档所需的; ownerPassword控制权限设置本身。 设置allowUserPrinting: true同时禁用其他权限标志允许接收者打印文档,但防止编辑、复制和注释。 有关可用权限标志的完整列表,请参阅IronPDF Node.js API参考

重要如果来源PDF已经是密码保护的,在使用fromFile()加载时提供每个文档的解密密码。 尝试合并加密文档而不提供其密码将导致错误。)]}


如何合并PDF并添加数字签名?

合并PDF并立即签署结果会生成一个覆盖所有源内容的单一签署文档。 在applySignature()以将数字证书附加到合并输出。

//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-signature.js
const IronPdf = require('ironpdf');

async function mergeAndSign(inputFiles, outputFile, pfxPath, pfxPassword) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Attach a digital signature using a PFX certificate
  await mergedPdf.applySignature(pfxPath, pfxPassword);
  await mergedPdf.toFile(outputFile);
}

mergeAndSign(
  ['section-a.pdf', 'section-b.pdf'],
  'signed-report.pdf',
  'certificate.pfx',
  'certpass'
);
//:path=/static-assets/pdf/content-code-examples/how-to/nodejs-merge-pdf/merge-with-signature.js
const IronPdf = require('ironpdf');

async function mergeAndSign(inputFiles, outputFile, pfxPath, pfxPassword) {
  const docs = await Promise.all(
    inputFiles.map(f => IronPdf.PdfDocument.fromFile(f))
  );
  const mergedPdf = await IronPdf.PdfDocument.merge(docs);

  // Attach a digital signature using a PFX certificate
  await mergedPdf.applySignature(pfxPath, pfxPassword);
  await mergedPdf.toFile(outputFile);
}

mergeAndSign(
  ['section-a.pdf', 'section-b.pdf'],
  'signed-report.pdf',
  'certificate.pfx',
  'certpass'
);
JAVASCRIPT

applySignature()方法将证书嵌入到PDF元数据中,以便读者验证文档完整性。 此工作流程在合同装配管道中很常见,其中多个部分在发布前组合并共同签署。 有关基于证书的签名的完整演练,请参阅数字签名示例

提示在需要一个证明整个合并文档的单一证书时,签署合并后的文档而不是单个源文件。


如何排除常见的PDF合并错误?

合并过程中大多数错误属于四类:文件缺失、内存耗尽、输入损坏和权限问题。 下表列出了最常见的原因以及如何解决它们。

常见PDF合并错误及其解决方案
错误可能原因解决方案
找不到文件路径错误或工作目录不匹配使用绝对路径或验证进程工作目录
JavaScript堆内存不足同时加载许多大PDF增加Node.js内存:node --max-old-space-size=4096 script.js
无效或损坏的PDF源文件损坏或不是有效的PDF在处理之前用PDF阅读器验证源文件
权限被拒输入没有读取访问权限或输出目录没有写入权限检查操作系统上的文件和目录权限
加密的源PDF输入PDF需要密码才能打开将密码作为第二个参数传给fromFile()

对于特定环境的设置问题,IronPDF变更日志记录已知问题和修复。 如果在检查上表后问题仍然存在,请将合并调用包装在try-catch块中,以显示库的完整错误信息。

注意在调用fromFile()之前,总是验证输入数组中的每个文件路径是否存在。 单个缺失的文件会导致整个Promise.all()调用被拒绝,取消合并。

Node.js本身提供了用于飞行前路径验证的有用工具。 Node.js fs.promises.access方法让您在传递给IronPDF之前检查文件是否可读。 对于关于社区开发人员如何处理类似合并错误场景的问题,在Node.js中合并PDF的Stack Overflow线程提供了额外的上下文。


在Node.js中合并PDF的下一步是什么?

上述示例涵盖最常见的合并场景:基本文件组合、页面范围选择、页眉和页脚注入、密码保护和数字签名。 IronPDF还支持在合并页面上管理PDF表单将新内容加盖到合并文档上,以及从最终输出中生成栅格化图像以进行预览生成。

开始您的30天免费试用以测试合并不带水印,或查看许可选项如果您准备部署。

准备看看IronPDF还能做些什么吗? 访问IronPDF for Node.js文档以获取完整的API演练和其他操作指南。

常见问题解答

如何在Node.js中将多个PDF文件合并为一个?

使用PdfDocument.fromFile()加载每个文件,将结果收集到一个数组中,将数组传递给PdfDocument.merge(),并使用toFile()保存输出。当合并三个或更多文档时,使用Promise.all()并行加载文件。

合并PDF时IronPDF是否保留格式?

是的。IronPDF保留每个源文档中的字体、图像、嵌入表单和页面几何体。合并后的输出保持输入数组中源文件出现顺序的每页的原始布局。

如何仅合并每个PDF中的特定页面?

在传入PdfDocument.merge()之前,在每个加载的文档上调用extractPages(startPage, endPage)。页面索引是从零开始的,因此第一页是索引0。返回的文档仅包含指定范围。

我可以为合并的PDF添加页眉和页脚吗?

可以。在合并后,调用结果文档上的addHtmlHeader()addHtmlFooter()。这两种方法都接受HTML字符串和一个选项对象。使用{page}{total-pages}占位符实现自动分页。

如何在Node.js中为合并的PDF设置密码保护?

使用安全选项对象调用saveAs(),指定userPasswordownerPassword和权限标志,例如allowUserPrintinguserPassword是打开文档所需的,ownerPassword控制权限设置。

如果合并失败并出现文件未找到错误怎么办?

验证所有输入文件路径是否相对于Node.js进程工作目录正确,或切换到绝对路径。使用fs.promises.access()确认每个文件在调用PdfDocument.fromFile()之前是可读的。

如果其中一个源PDF被加密怎么办?

尝试加载未提供密码的加密PDF将抛出错误并拒绝整个Promise.all()调用。在合并之前,将文档密码作为第二个参数提供给fromFile()

我需要额度密钥才能使用IronPDF合并PDF吗?

在开发期间,IronPDF不需要许可证密钥,但输出文档中会包含试用水印。在部署到生产之前配置有效许可证密钥以消除水印并启用完整功能。

Darrius Serrant
全栈软件工程师(WebOps)

Darrius Serrant 拥有迈阿密大学的计算机科学学士学位,目前在 Iron Software 担任全栈 WebOps 市场工程师。从小就被编码吸引,他认为计算机既神秘又易于接触,使其成为创意和问题解决的理想媒介。

在 Iron Software,Darrius 喜欢创造新事物,并简化复杂概念以使其更易理解。作为我们常驻的开发者之一,他还自愿教授学生,与下一代分享他的专业知识。

对于 Darrius 来说,他的工作令人满意,因为它被重视并产生真正的影响。

准备开始了吗?
版本: 2026.6 刚刚发布
Still Scrolling Icon

还在滚动吗?

想快速获得证据?
运行示例看着你的HTML代码变成PDF文件。