如何使用Node.js將多個PDF文件合併為單一PDF
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();最小工作流程(5個步驟)
- Install IronPDF:
npm install ironpdf - 導入程式庫:
const IronPdf = require('ironpdf') - 使用
PdfDocument.fromFile()載入每個PDF文件 - 使用
PdfDocument.merge()合併載入的文件 - 使用
toFile()保存結果
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);
})();Promise.all()並行載入源文件,而不是一次載入一個,這在處理大型集合時很重要。 merge()調用將按陣列順序連接文件,將文件按您希望它們在輸出中出現的順序放置在陣列中。
fromFile()方法本身不解析相對於腳本文件的路徑。程式碼的每一部分做了什麼?
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);extractPages(startPage, endPage)接受零基頁面索引。 傳遞0, 2提取前三頁。 迴圈構建一個頁面範圍文件的陣列,按它們在merge()將它們連接為最終輸出。
這種模式在從簽名頁、附錄和單獨文件中儲存的封面表中組裝合同時很有用。 您可以從每個來源文件中精確收集所需的頁面,而不需在磁盤上複製文件。
如何向合併的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');{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');userPassword是開啟文件所必需的; ownerPassword控制權限設置本身。 在禁用其他權限標誌的同時設置allowUserPrinting: true,允許接收者列印文件,但防止編輯、複製和註釋。 有關可用權限標誌的完整列表,請參見IronPDF Node.js API參考。
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'
);applySignature()方法將證書嵌入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之前檢查文件是否可讀。 有關社區開發者如何處理類似合併錯誤場景的問題,Stack Overflow相關執行緒提供了額外的背景資訊。
在Node.js中合併PDF的下一步是什麼?
以上範例涵蓋了最常見的合併場景:基本文件合併、頁面範圍選擇、頁眉和頁腳插入、密碼保護和數位簽名。 IronPDF還支持管理合併頁面上的PDF表單、在合併文件上蓋上新內容和將最終輸出轉換為光柵圖像以進行預覽生成。
開始您的免費30天試用以測試合併而無浮水印,或者如果您已經準備好部署,可以查看授權選項。
準備好看看IronPDF還能做什麼嗎? 存取IronPDF for Node.js文件以獲取完整的API指南和其他操作指南。
常見問題
如何在 Node.js 中將多個 PDF 文件合併為一個?
using PdfDocument.fromFile() 載入每個文件,將結果收集到一個陣列中,然後將陣列傳遞給 PdfDocument.merge(),並使用 toFile() 保存輸出。在合併三個或更多文件時,使用 Promise.all() 並行載入文件。
IronPDF 在合併 PDF 時會保留格式嗎?
會的。IronPDF 保留每個源文件的字體、圖像、嵌入的表單和頁面幾何。合併的輸出保持輸入陣列中每個頁面的原始佈局順序。
如何僅合併每個 PDF 的特定頁面?
在將每個載入的文件傳遞給 PdfDocument.merge() 之前,調用 extractPages(startPage, endPage)。頁面索引是從零開始的,第一頁是索引 0。返回的文件僅包含指定的範圍。
我能在合併的 PDF 中新增頁眉和頁腳嗎?
可以。合併後,在結果文件上調用 addHtmlHeader() 和 addHtmlFooter()。這兩個方法都接受 HTML 字串和選項物件。使用 {page} 和 {total-pages} 占位符自動進行頁碼編號。
如何在 Node.js 中為合併的 PDF 設置密碼保護?
使用安全選項物件調用 saveAs(),指定 userPassword、ownerPassword 和如 allowUserPrinting等權限標誌。userPassword 是開啟文件所需的密碼;ownerPassword 則控製權限設置。
如果合併過程中出現找不到文件錯誤,我該怎麼辦?
驗證所有輸入文件路徑相對於 Node.js 過程工作目錄是否正確,或切換為絕對路徑。在調用 PdfDocument.fromFile() 之前,使用 fs.promises.access() 確認每個文件都是可讀的。
如果其中一個源PDF被加密會怎麼樣?
如果沒有提供其密碼就嘗試載入加密的PDF,將會丟出錯誤並拒絕整個 Promise.all() 調用。合併前,將文件密碼作為fromFile()的第二個參數提供。
合併PDF需要使用IronPDF授權金鑰嗎?
IronPDF在開發過程中不需要授權金鑰,但輸出文件會包含試用水印。在部署到生產環境之前配置有效的授權金鑰,以移除水印並啟用完整功能。





