Node.js實(shí)現(xiàn)修改文件字符集功能的具體過程
前言
在日常生活、工作中,我們經(jīng)常會(huì)遇到需要處理不同編碼格式的文件。有時(shí),在嘗試打開這些文件時(shí)會(huì)遇到亂碼,原因通常是文件的編碼與我們使用的文本編輯器或編程語言的默認(rèn)編碼不匹配。這種情況尤其常見于一些歷史遺留的文件或從不同系統(tǒng)中導(dǎo)出的數(shù)據(jù)。
手動(dòng)處理這種問題不僅耗時(shí),而且容易出錯(cuò)。如果文件數(shù)量較多,更是令人頭疼。為了解決這個(gè)問題,我編寫了一個(gè)腳本,自動(dòng)化地將大量文件的編碼格式轉(zhuǎn)換為常用的 UTF-8。這篇文章將介紹該腳本的實(shí)現(xiàn)思路和具體實(shí)現(xiàn)過程,希望對遇到類似問題的朋友有所幫助。

實(shí)現(xiàn)思路
實(shí)現(xiàn)的思路其實(shí)非常簡單:遞歸讀取指定文件夾下的所有文件,然后檢測每個(gè)文件的編碼格式,將其轉(zhuǎn)換為 UTF-8 并寫回文件。通過這種方式,我們能夠確保所有文件都統(tǒng)一為 UTF-8 編碼,從而避免亂碼問題。

具體實(shí)現(xiàn)
我們使用 Node.js 來實(shí)現(xiàn)這個(gè)功能。Node.js 提供了豐富的文件系統(tǒng)操作 API,以及強(qiáng)大的第三方庫來簡化編碼轉(zhuǎn)換等操作。下面是具體的實(shí)現(xiàn)過程。
遞歸讀取文件
首先,我們需要遞歸讀取指定目錄下的所有文件。這可以通過 Node.js 提供的 fs.readdir 方法來實(shí)現(xiàn)。這里有兩個(gè)很有用的配置屬性:
withFileTypes- 當(dāng)設(shè)置為true時(shí),readdir方法返回的將是fs.Dirent對象數(shù)組。這個(gè)對象提供了關(guān)于文件類型的信息,比如是否為目錄等。recursive- 當(dāng)設(shè)置為true時(shí),可以遞歸讀取目錄及其子目錄下的所有文件。
通過這兩個(gè)屬性,我們可以輕松地獲取指定目錄下的所有文件路徑,并判斷它們是否是文件夾。下面是具體代碼實(shí)現(xiàn):
/**
* 遞歸獲取文件夾下所有文件
* @param {string} path
* @returns
*/
async function readAllBook(path) {
let filesList = [];
const files = await readdir(path, { withFileTypes: true, recursive: true });
for (const file of files) {
if (file.isDirectory()) continue
const filePath = join(file.path, file.name);
filesList.push(filePath);
}
return filesList;
}
調(diào)用這個(gè)函數(shù)后,我們可以獲得指定目錄下所有文件的路徑,方便后續(xù)處理。

獲取字符集編碼
嘗試讀取文件內(nèi)容
通常在使用 Node.js 讀取文件時(shí),我們會(huì)指定編碼方式,比如 utf-8。然而,如果文件的編碼格式與我們指定的不一致,就會(huì)出現(xiàn)亂碼。
await readFile('book/book1.txt', { encoding: 'utf-8' }).then(async (data) => {
console.log(data);
})
如果文件本身并不是 utf-8 編碼的,讀取時(shí)就可能會(huì)出現(xiàn)亂碼。為了正確讀取文件,我們需要首先檢測它的編碼格式。

Node 支持的字符編碼
在處理文件編碼的時(shí)候,了解 Node.js 支持的字符編碼對我們來說還是挺重要的。Node.js 提供了一系列的編碼選項(xiàng),可以在 Buffer 和字符串之間進(jìn)行轉(zhuǎn)換,以下是 Node.js 支持的主要字符編碼和它們的用途。
常用字符編碼
utf8(別名:utf-8): 這是最常用的編碼格式,支持多字節(jié)編碼的 Unicode 字符。它能很好地處理包含各種字符的文本文件,是我們轉(zhuǎn)換目標(biāo)的首選編碼。utf16le(別名:utf-16le): 這個(gè)編碼格式也支持多字節(jié)編碼的 Unicode 字符,但與utf8不同,utf16le使用 2 或 4 個(gè)字節(jié)來編碼每個(gè)字符。它常用于處理東亞字符集。latin1: 這個(gè)編碼代表ISO-8859-1,只支持U+0000到U+00FF范圍內(nèi)的 Unicode 字符。它使用單字節(jié)編碼,對于某些老舊系統(tǒng)或文件,這種編碼可能依然常見。
二進(jìn)制編碼
在處理一些需要編碼二進(jìn)制數(shù)據(jù)為字符串,或從字符串解碼二進(jìn)制數(shù)據(jù)的場景時(shí),以下編碼格式也可能會(huì)用到:
base64: 這是最常見的二進(jìn)制到文本的編碼方式,常用于編碼圖像、音頻文件等。hex: 將每個(gè)字節(jié)編碼為兩個(gè)十六進(jìn)制字符,常用于處理加密數(shù)據(jù)。
舊版字符編碼
ascii: 這個(gè)編碼僅適用于 7 位 ASCII 數(shù)據(jù)。在現(xiàn)代應(yīng)用中通常很少用到,因?yàn)樗鼰o法處理非英語字符。binary: 這是latin1的別名,用于處理簡單的二進(jìn)制數(shù)據(jù)。ucs2和ucs-2: 這些是utf16le的別名,曾經(jīng)用于處理不支持U+FFFF以上字符的場景。
jschardet
jschardet 是一個(gè)字符編碼的檢測器,可以用來檢測文本文件或數(shù)據(jù)流的字符編碼的工具。它的工作原理就是通過分析文本中的字節(jié)模式,嘗試匹配已知的編碼方式。支持 20 多種字符編碼,但要注意的是檢測出來的結(jié)果不能保證百分之百的準(zhǔn)確。

我們使用 npm i jschardet 安裝 jschardet 之后,就可以使用 detect 方法獲取字符編碼
import jschardet from 'jschardet';
await readFile('book/book1.txt').then(async (data) => {
console.log(jschardet.detect(data));
})
這個(gè)方法會(huì)返回一個(gè)對象:encoding 和 confidence, encoding 是檢測的編碼,confidence 是這個(gè)檢測結(jié)果的置信度。
每個(gè)檢測器都會(huì)根據(jù)它的分析給出一個(gè)置信度(Confidence Level),置信度最高的編碼就會(huì)被選中。就像我們之前說的,因?yàn)楹芏嗑幋a很相似,所以這個(gè)檢測并不是百分之百準(zhǔn)確,但 chardet 設(shè)計(jì)得比較聰明,通常能給出一個(gè)比較靠譜的結(jié)果。

轉(zhuǎn)換字符集編碼
現(xiàn)在我們拿到了文件內(nèi)容的字符編碼,需要一個(gè)轉(zhuǎn)換器將內(nèi)容轉(zhuǎn)換為 utf-8, 這時(shí)我們需要引入一個(gè)新的庫 iconv-lite
iconv-lite 是一個(gè)用于 Node.js 的輕量級(jí)字符編碼轉(zhuǎn)換庫。它允許你在 Node.js 應(yīng)用程序中進(jìn)行字符編碼的轉(zhuǎn)換和處理,特別是處理非 UTF-8 編碼的數(shù)據(jù)。與其他類似的庫相比,iconv-lite 更加輕便,因?yàn)樗灰蕾囃獠康?C 庫或者原生模塊,完全用純 JavaScript 實(shí)現(xiàn)。
import iconv from 'iconv-lite';
await readFile('book/book1.txt').then(async (data) => {
const { encoding } = jschardet.detect(data);
console.log(iconv.decode(data, encoding));
})
通過以上代碼,我們可以將文件內(nèi)容正確地解碼為 UTF-8 格式,并輸出到控制臺(tái)。

獲取到轉(zhuǎn)碼內(nèi)容的后,我們就可以遍歷之前獲取的文件列表,全部進(jìn)行轉(zhuǎn)碼重新寫入文件了,這個(gè)步驟很簡單,不單獨(dú)進(jìn)行講解了,可以直接參考下面的完整代碼。
完整代碼
import { readdir, readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import iconv from 'iconv-lite';
import jschardet from 'jschardet';
/**
* 遞歸獲取文件夾下所有文件
* @param {string} path
* @returns
*/
async function readAllBook(path) {
let filesList = [];
const files = await readdir(path, { withFileTypes: true, recursive: true });
for (const file of files) {
if (file.isDirectory()) continue
const filePath = join(file.path, file.name);
filesList.push(filePath);
}
return filesList;
}
readAllBook('./book').then(async (files) => {
console.log('文件重寫開始,請稍候...');
for (const file of files) {
await readFile(file).then(async (data) => {
// 獲取讀取的內(nèi)容編碼
const charset = jschardet.detect(data)
// 轉(zhuǎn)換內(nèi)容編碼
const fileContent = iconv.decode(data, charset.encoding || 'GB2312')
// 重新寫回文件
await writeFile(file, fileContent, { encoding: 'utf-8' }).catch((err) => {
console.log(file + '文件寫入失敗', err);
});
});
}
console.log('文件重寫完成!');
});
結(jié)語
通過使用 Node.js 和一些實(shí)用的第三方庫,我們可以快速有效地解決這個(gè)問題。希望這篇文章能夠幫助你更好地理解文件編碼轉(zhuǎn)換,并應(yīng)用到實(shí)際生活和工作中。
以上就是Node.js實(shí)現(xiàn)修改文件字符集功能的具體過程的詳細(xì)內(nèi)容,更多關(guān)于Node.js修改文件字符集的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
node跨域轉(zhuǎn)發(fā) express+http-proxy-middleware的使用
這篇文章主要介紹了node跨域轉(zhuǎn)發(fā) express+http-proxy-middleware的使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05
Linux環(huán)境部署node服務(wù)并啟動(dòng)詳細(xì)步驟
最近用node.js開發(fā)了一個(gè)web項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于Linux環(huán)境部署node服務(wù)并啟動(dòng)的詳細(xì)步驟,文中通過圖文以及示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
詳解基于electron制作一個(gè)node壓縮圖片的桌面應(yīng)用
這篇文章主要介紹了詳解基于electron制作一個(gè)node壓縮圖片的桌面應(yīng)用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
node.js使用redis儲(chǔ)存session的方法
這篇文章主要介紹了node.js使用redis儲(chǔ)存session的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09

