如何使用 Node.js 將多個 PDF 檔案合併為單一 PDF 檔案
IronPDF 讓您只需幾行代碼,即可在 Node.js 中將多個 PDF 檔案合併為單一文件。 使用 PdfDocument.fromFile() 載入每個檔案,將陣列傳遞給 PdfDocument.merge(),並使用 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 個步驟)
- 安裝 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.merge() 接受一個 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.fromFile():從磁碟讀取 PDF 檔案,並傳回一個PdfDocument物件。 完整的函式簽名請參閱 IronPDF for Node.js API 參考手冊。Promise.all():同時執行所有檔案載入操作,從而縮短多文件合併的總載入時間。 此模式同樣適用於多執行緒及並行 PDF 生成情境。PdfDocument.merge():將已載入的文件陣列串接成單一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, 0 僅會擷取第一頁,而 0, 2 則會擷取前三頁。 該迴圈會依照 ranges 中出現的順序,建立一個包含頁面範圍文件陣列,然後 merge() 將它們串接成最終輸出。
此模式適用於將儲存於不同檔案中的簽名頁、附錄及封面頁組合成合約時。 您可以精準地從每個來源收集重要的頁面,而無需在磁碟上重複儲存檔案。
如何在合併後的 PDF 中添加頁首和頁尾?
合併後,請在生成的文件中呼叫 addHtmlHeader() 和 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');{page} 和 {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 for Node.js API 參考手冊。
fromFile() 提供各文件的解密密碼。 若嘗試在未提供密碼的情況下合併加密文件,將會導致錯誤。)}]如何合併 PDF 並添加數位簽名?
將 PDF 合併後立即對合併結果進行簽署,即可產生一份涵蓋所有原始內容的單一簽署文件。 請在 merge() 之後加入 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 變更紀錄中記載了已知問題及修正方案。 若查閱上表後問題仍未解決,請將 merge 呼叫包覆在 try-catch 區塊中,以顯示該函式庫的完整錯誤訊息。
fromFile() 之前,請務必驗證輸入陣列中的每個檔案路徑是否存在。 只要缺少一個檔案,就會導致整個 Promise.all() 呼叫失敗,進而取消合併。Node.js 本身提供了用於飛行前路徑驗證的實用工具。 Node.js 的 fs.promises.access 方法可讓您在將檔案傳遞給 IronPDF 前,先檢查該檔案是否可讀。 若想了解社群開發者如何處理類似的合併錯誤情境,Stack Overflow 上關於在 Node.js 中合併 PDF 的討論串可提供更多背景資訊。
在 Node.js 中合併 PDF 的下一步該怎麼做?
上述範例涵蓋了最常見的合併情境:基本檔案合併、頁面範圍選取、頁首與頁尾插入、密碼保護,以及數位簽章。 IronPDF 亦支援跨合併頁面的 PDF 表單管理、將新內容疊印至合併文件,以及從最終輸出產生點陣圖以供預覽。
立即開始 30 天試用,體驗無浮水印的合併功能;若您已準備好部署,亦可查看授權方案。
準備好探索 IronPDF 的更多功能了嗎? 請參閱 IronPDF for Node.js 文件,以獲取完整的 API 操作指南及更多實用教學。
常見問題
如何在 Node.js 中將多個 PDF 檔案合併為一個?
使用 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 設定密碼保護?
請透過傳入指定 userPassword、ownerPassword 以及 allowUserPrinting 等權限標誌的安全選項物件,來呼叫 saveAs() 方法。userPassword 是開啟文件所需的密碼;ownerPassword 則用於控制權限設定。
若合併操作因「檔案未找到」錯誤而失敗,我該怎麼辦?
請確認所有輸入檔案路徑均為相對於 Node.js 執行程序工作目錄的相對路徑,或改用絕對路徑。在呼叫 PdfDocument.fromFile() 之前,請使用 fs.promises.access() 確認每個檔案皆可讀取。
如果其中一個原始 PDF 檔案經過加密,該怎麼辦?
若未提供密碼即嘗試載入加密的 PDF 檔案,將會引發錯誤並導致整個 Promise.all() 呼叫失敗。請在合併前,將文件密碼作為 fromFile() 的第二個參數傳入。
使用 IronPDF 合併 PDF 檔案是否需要授權金鑰?
IronPDF 在開發階段無需授權金鑰即可運作,但產出的文件會包含試用版浮水印。請在部署至生產環境前設定有效的授權金鑰,以移除浮水印並啟用完整功能。





