JavaScript實(shí)現(xiàn)批量將txt文件轉(zhuǎn)為pdf
最近遇到了這樣一個(gè)場(chǎng)景,需要將很多的txt文件轉(zhuǎn)成pdf文件,一個(gè)一個(gè)手動(dòng)轉(zhuǎn)換不僅累、效率還不高,于是便寫了這么一個(gè)插件來(lái)解放自己,可以一鍵批量進(jìn)行自動(dòng)轉(zhuǎn)換~

功能說(shuō)明
這個(gè)插件的核心目標(biāo)是「降低 txt 轉(zhuǎn) pdf 的操作成本」,支持單文件轉(zhuǎn)換和多文件批量轉(zhuǎn)換。
1. 單文件轉(zhuǎn)換
針對(duì)「偶爾需要轉(zhuǎn)換單個(gè) txt 文件」的場(chǎng)景,支持手動(dòng)選擇指定的.txt文件,自定義輸出PDF的保存目錄。轉(zhuǎn)換后的PDF會(huì)自動(dòng)添加標(biāo)題、段落縮進(jìn)、頁(yè)眉(文件名)和頁(yè)腳(頁(yè)碼),排版符合中文閱讀習(xí)慣,無(wú)需后續(xù)手動(dòng)調(diào)整格式。
2. 多文件批量轉(zhuǎn)換
針對(duì)「大量txt文件需要統(tǒng)一處理」的場(chǎng)景,只需選擇存放txt文件的目錄,插件會(huì)自動(dòng)掃描目錄下所有.txt文件(忽略其他格式),按文件名順序批量轉(zhuǎn)換,并將所有PDF輸出到指定目錄。
功能實(shí)現(xiàn)
1. 命令行交互:獲取用戶配置
通過(guò)命令行獲取關(guān)鍵信息:是轉(zhuǎn)換單個(gè)文件還是批量轉(zhuǎn)換?文件/目錄在哪里?PDF要存到哪里?這里用到了@jyeontu/j-inquirer(基于inquirer的增強(qiáng)庫(kù)),支持可視化選擇文件和目錄,比手動(dòng)輸入路徑更直觀。
實(shí)現(xiàn)邏輯分為兩步:
第一步:選擇轉(zhuǎn)換模式
彈出選項(xiàng)列表,讓用戶選擇「單文件轉(zhuǎn)換」或「批量轉(zhuǎn)換」,不同模式對(duì)應(yīng)不同的后續(xù)交互——單文件需要選具體的.txt文件,批量轉(zhuǎn)換需要選存放txt的目錄。

第二步:獲取路徑信息
根據(jù)選擇的模式,動(dòng)態(tài)生成路徑選擇項(xiàng):?jiǎn)挝募J斤@示「文件選擇器」,批量模式顯示「目錄選擇器」,最后統(tǒng)一讓用戶選擇PDF的輸出目錄。
關(guān)鍵代碼片段(簡(jiǎn)化版):
const getConfig = async () => {
// 選擇轉(zhuǎn)換模式
const actionType = await new inquirer([
{ type: "list", name: "action", message: "請(qǐng)選擇操作", choices: ["單文件轉(zhuǎn)換", "批量轉(zhuǎn)換"] }
]).prompt();
// 動(dòng)態(tài)生成路徑選擇項(xiàng)
const options = [];
if (actionType.action === "單文件轉(zhuǎn)換") {
options.push({
type: "file", name: "txtFilePath", message: "選擇txt文件", dirname: process.cwd(), pathType: "absolute"
});
} else {
options.push({
type: "folder", name: "txtDir", message: "選擇txt目錄", dirname: process.cwd(), pathType: "absolute"
});
}
// 統(tǒng)一選擇PDF輸出目錄
options.push({
type: "folder", name: "pdfFilePath", message: "選擇PDF輸出目錄", dirname: process.cwd(), pathType: "absolute"
});
const answers = await new inquirer(options).prompt();
return { ...actionType, ...answers };
};
交互效果類似這樣:
? 請(qǐng)選擇操作: 批量轉(zhuǎn)換
? 選擇txt目錄: E:\文檔\txt文件
? 選擇PDF輸出目錄: E:\文檔\PDF文件
用戶只需通過(guò)鍵盤上下鍵和回車鍵,就能完成所有配置,無(wú)需記憶復(fù)雜命令。
2. 文件轉(zhuǎn)換:txt轉(zhuǎn)pdf的核心邏輯
txt轉(zhuǎn)pdf的核心挑戰(zhàn)是「保留排版樣式」——直接將文本內(nèi)容寫入PDF會(huì)導(dǎo)致格式混亂(比如沒(méi)有段落、沒(méi)有縮進(jìn)),因此采用「HTML中間層」方案:先將txt內(nèi)容轉(zhuǎn)換為帶樣式的HTML,再用html-pdf-node將HTML渲染為PDF。
整個(gè)轉(zhuǎn)換流程分為3步:
第一步:讀取txt內(nèi)容
用fs-extra的readFile方法異步讀取txt文件,同時(shí)指定編碼為utf-8,確保中文內(nèi)容不會(huì)亂碼。
const content = await fs.readFile(txtFilePath, 'utf-8');
第二步:生成帶樣式的HTML
將txt中的換行符拆分為段落,過(guò)濾空行,添加中文排版樣式(首行縮進(jìn)2字符、行高1.8、字體為微軟雅黑),同時(shí)加入標(biāo)題、頁(yè)眉頁(yè)腳占位符。
比如將txt中的"第一部分:項(xiàng)目概述\n\n這是項(xiàng)目的基本介紹。"轉(zhuǎn)換為:
<div class="title">項(xiàng)目概述</div> <p style="text-indent:2em;">第一部分:項(xiàng)目概述</p> <p style="text-indent:2em;">這是項(xiàng)目的基本介紹。</p>
第三步:HTML渲染為PDF
用html-pdf-node加載HTML文件(先創(chuàng)建臨時(shí)HTML文件,避免內(nèi)存溢出),配置PDF參數(shù):A4格式、2cm邊距、顯示頁(yè)眉頁(yè)腳,最后將渲染后的PDF緩沖區(qū)寫入指定路徑。
關(guān)鍵代碼片段(簡(jiǎn)化版):
async convertSmallFile(content, fileName, pdfFilePath) {
// 生成HTML
const htmlContent = this.generateHTML(content, fileName);
const tempHtmlPath = path.join(__dirname, "temp.html");
await fs.writeFile(tempHtmlPath, htmlContent);
try {
// 配置PDF選項(xiàng)
const options = {
format: "A4",
margin: { top: "2cm", right: "2cm", bottom: "2cm", left: "2cm" },
headerTemplate: `<div style="text-align:center; color:#666;">${fileName}</div>`,
footerTemplate: `<div style="text-align:center; color:#666;">第 <span class="pageNumber"></span> 頁(yè)</div>`
};
// 渲染PDF
const buffer = await htmlpdf.generatepdf({ url: `file://${tempHtmlPath}` }, options);
await fs.writeFile(pdfFilePath, buffer);
} finally {
// 清理臨時(shí)文件
await fs.remove(tempHtmlPath);
}
}
3. 大文件分割:避免內(nèi)存溢出
如果遇到幾千頁(yè)的大文件(比如中長(zhǎng)篇小說(shuō)),直接轉(zhuǎn)換會(huì)導(dǎo)致Node.js內(nèi)存溢出(默認(rèn)單進(jìn)程內(nèi)存限制較低)。因此需要添加「大文件分段處理」邏輯:當(dāng)txt文件字符數(shù)超過(guò)50萬(wàn)時(shí),自動(dòng)拆分為多個(gè)片段,每個(gè)片段生成獨(dú)立的「部分PDF」,最后合并為單個(gè)文件。
- 第一步:按換行符拆分文本將txt內(nèi)容按
\n拆分為行數(shù)組,確保每個(gè)片段的末尾都是完整的行。 - 第二步:控制片段大小循環(huán)將行添加到當(dāng)前片段,當(dāng)當(dāng)前片段字符數(shù)接近30萬(wàn)(閾值)時(shí),保存當(dāng)前片段并開(kāi)始新片段。
- 第三步:生成片段PDF每個(gè)片段生成對(duì)應(yīng)的PDF(文件名帶
_part1、_part2后綴),同時(shí)記錄片段路徑,為后續(xù)合并做準(zhǔn)備。
關(guān)鍵代碼片段(簡(jiǎn)化版):
splitContent(content, maxLength) {
const segments = [];
const lines = content.split("\n");
let currentSegment = "";
for (const line of lines) {
if ((currentSegment + line + "\n").length > maxLength && currentSegment) {
segments.push(currentSegment.trim());
currentSegment = line + "\n";
} else {
currentSegment += line + "\n";
}
}
if (currentSegment.trim()) segments.push(currentSegment.trim());
return segments;
}
4. 文件合并:將分段PDF整合成一個(gè)
分段生成的「部分PDF」需要合并為單個(gè)文件,才符合用戶的使用習(xí)慣。這里用到了pdf-lib(輕量級(jí)PDF處理庫(kù)),支持加載、復(fù)制、合并PDF頁(yè)面,且兼容性良好。
合并邏輯分為3步:
- 第一步:檢查是否存在已生成的片段先判斷所有「部分PDF」是否已存在(比如上次轉(zhuǎn)換到一半中斷了),如果全部存在,直接合并無(wú)需重新生成,實(shí)現(xiàn)「斷點(diǎn)續(xù)轉(zhuǎn)」。
- 第二步:復(fù)制PDF頁(yè)面創(chuàng)建一個(gè)空的PDF文檔,循環(huán)加載每個(gè)「部分PDF」,復(fù)制其中的所有頁(yè)面到空文檔中。
- 第三步:保存合并后的PDF將合并后的PDF寫入最終路徑,同時(shí)刪除所有「部分PDF」,避免冗余文件殘留。
關(guān)鍵代碼片段(簡(jiǎn)化版):
async mergeExistingParts(partFiles, outputPath) {
const mergedpdf = await PDFLib.PDFDocument.create();
for (const partFile of partFiles) {
const partBuffer = await fs.readFile(partFile);
const partpdf = await PDFLib.PDFDocument.load(partBuffer);
// 復(fù)制頁(yè)面到合并文檔
const copiedPages = await mergedpdf.copyPages(partpdf, partpdf.getPageIndices());
copiedPages.forEach(page => mergedpdf.addPage(page));
}
// 保存合并結(jié)果
const mergedBytes = await mergedpdf.save();
await fs.writeFile(outputPath, mergedBytes);
// 清理部分文件
partFiles.forEach(file => fs.remove(file));
}
工具使用
目前該工具已經(jīng)打包發(fā)布到npm上,可以直接使用命令安裝。
安裝
npm install -g jyeontu
目前該工具中集成了很多實(shí)用的功能,具體可以輸入命令jyeontu -h查看。

使用
需要使用 txt轉(zhuǎn)pdf功能可以按以下步驟操作。
jyeontu file

選擇txt轉(zhuǎn)pdf

后續(xù)根據(jù)提示進(jìn)行操作即可~

源碼地址
這個(gè)工具的完整源碼已開(kāi)源,支持直接克隆使用,也歡迎大家提Issue或PR改進(jìn)功能~
Gitee gitee.com/zheng_yongtao/jyeontu-cli.git
GitHub github.com/yongtaozheng/jyeontu-cli.git
到此這篇關(guān)于JavaScript實(shí)現(xiàn)批量將txt文件轉(zhuǎn)為pdf的文章就介紹到這了,更多相關(guān)JavaScript txt轉(zhuǎn)pdf內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript使用Blob文件流下載txt、pdf、圖片等文件,自定義下載文件名
- vue中pdf.js的使用之pdf顯示、跳轉(zhuǎn)指定頁(yè)面及高亮關(guān)鍵詞
- 基于JavaScript實(shí)現(xiàn)HTML到PDF的轉(zhuǎn)換指南
- Node.js實(shí)現(xiàn)文本與pdf相互轉(zhuǎn)換的代碼詳解
- 使用Nodejs編寫一個(gè)腳本實(shí)現(xiàn)markdown轉(zhuǎn)pdf功能
- node.js實(shí)現(xiàn)pdf與圖片互轉(zhuǎn)代碼示例
- 前端使用pdf.js實(shí)現(xiàn)pdf轉(zhuǎn)為圖片
相關(guān)文章
webpack DllPlugin xxx is not defined解決辦法
這篇文章主要介紹了webpack DllPlugin xxx is not defined解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Javascript的表單與驗(yàn)證-非空驗(yàn)證
JavaScript 可用來(lái)在數(shù)據(jù)被送往服務(wù)器前對(duì) HTML 表單中的這些輸入數(shù)據(jù)進(jìn)行驗(yàn)證。本文給大家介紹javascript的表單與驗(yàn)證-非空驗(yàn)證,對(duì)javascript表單驗(yàn)證相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-03-03
Next.js應(yīng)用轉(zhuǎn)換為TypeScript方法demo
這篇文章主要為大家介紹了Next.js應(yīng)用轉(zhuǎn)換為TypeScript方法demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
javascript下高性能字符串連接StringBuffer類
使用StringBuffer類比使用加號(hào)節(jié)省50%左右的時(shí)間,大家對(duì)于大數(shù)據(jù)的連接最好使用這個(gè)方法。2010-08-08
JavaScript中的連續(xù)賦值問(wèn)題實(shí)例分析
這篇文章主要介紹了JavaScript中的連續(xù)賦值問(wèn)題,結(jié)合實(shí)例形式分析了javascript賦值語(yǔ)句以及連續(xù)賦值操作相關(guān)用法與操作注意事項(xiàng),需要的朋友可以參考下2019-07-07
js實(shí)現(xiàn)的點(diǎn)擊數(shù)量加一可操作數(shù)據(jù)庫(kù)
這篇文章主要介紹了js如何實(shí)現(xiàn)的點(diǎn)擊數(shù)量加一操作數(shù)據(jù)庫(kù),需要的朋友可以參考下2014-05-05

