likes
comments
collection
share

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

作者站长头像
站长
· 阅读数 45

前言

在日常生活、工作中,我们经常会遇到需要处理不同编码格式的文件。有时,在尝试打开这些文件时会遇到乱码,原因通常是文件的编码与我们使用的文本编辑器或编程语言的默认编码不匹配。这种情况尤其常见于一些历史遗留的文件或从不同系统中导出的数据。

手动处理这种问题不仅耗时,而且容易出错。如果文件数量较多,更是令人头疼。为了解决这个问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的 UTF-8。这篇文章将介绍该脚本的实现思路和具体实现过程,希望对遇到类似问题的朋友有所帮助。

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

实现思路

实现的思路其实非常简单:递归读取指定文件夹下的所有文件,然后检测每个文件的编码格式,将其转换为 UTF-8 并写回文件。通过这种方式,我们能够确保所有文件都统一为 UTF-8 编码,从而避免乱码问题。

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

具体实现

我们使用 Node.js 来实现这个功能。Node.js 提供了丰富的文件系统操作 API,以及强大的第三方库来简化编码转换等操作。下面是具体的实现过程。

递归读取文件

首先,我们需要递归读取指定目录下的所有文件。这可以通过 Node.js 提供的 fs.readdir 方法来实现。这里有两个很有用的配置属性:

  • withFileTypes - 当设置为 true 时,readdir 方法返回的将是 fs.Dirent 对象数组。这个对象提供了关于文件类型的信息,比如是否为目录等。
  • recursive - 当设置为 true 时,可以递归读取目录及其子目录下的所有文件。

通过这两个属性,我们可以轻松地获取指定目录下的所有文件路径,并判断它们是否是文件夹。下面是具体代码实现:

/**
 * 递归获取文件夹下所有文件
 * @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;
}

调用这个函数后,我们可以获得指定目录下所有文件的路径,方便后续处理。

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

获取字符集编码

尝试读取文件内容

通常在使用 Node.js 读取文件时,我们会指定编码方式,比如 utf-8。然而,如果文件的编码格式与我们指定的不一致,就会出现乱码。

await readFile('book/book1.txt', { encoding: 'utf-8' }).then(async (data) => {
	console.log(data);
})

如果文件本身并不是 utf-8 编码的,读取时就可能会出现乱码。为了正确读取文件,我们需要首先检测它的编码格式。

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

Node 支持的字符编码

在处理文件编码的时候,了解 Node.js 支持的字符编码对我们来说还是挺重要的。Node.js 提供了一系列的编码选项,可以在 Buffer 和字符串之间进行转换,以下是 Node.js 支持的主要字符编码和它们的用途。

常用字符编码
  • utf8(别名:utf-8: 这是最常用的编码格式,支持多字节编码的 Unicode 字符。它能很好地处理包含各种字符的文本文件,是我们转换目标的首选编码。

  • utf16le(别名:utf-16le: 这个编码格式也支持多字节编码的 Unicode 字符,但与 utf8 不同,utf16le 使用 2 或 4 个字节来编码每个字符。它常用于处理东亚字符集。

  • latin1: 这个编码代表 ISO-8859-1,只支持 U+0000U+00FF 范围内的 Unicode 字符。它使用单字节编码,对于某些老旧系统或文件,这种编码可能依然常见。

二进制编码

在处理一些需要编码二进制数据为字符串,或从字符串解码二进制数据的场景时,以下编码格式也可能会用到:

  • base64: 这是最常见的二进制到文本的编码方式,常用于编码图像、音频文件等。

  • hex: 将每个字节编码为两个十六进制字符,常用于处理加密数据。

旧版字符编码
  • ascii: 这个编码仅适用于 7 位 ASCII 数据。在现代应用中通常很少用到,因为它无法处理非英语字符。

  • binary: 这是 latin1 的别名,用于处理简单的二进制数据。

  • ucs2ucs-2: 这些是 utf16le 的别名,曾经用于处理不支持 U+FFFF 以上字符的场景。

jschardet

jschardet 是一个字符编码的检测器,可以用来检测文本文件或数据流的字符编码的工具。它的工作原理就是通过分析文本中的字节模式,尝试匹配已知的编码方式。支持 20 多种字符编码,但要注意的是检测出来的结果不能保证百分之百的准确。

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

我们使用 npm i jschardet 安装 jschardet 之后,就可以使用 detect 方法获取字符编码

import jschardet from 'jschardet';

await readFile('book/book1.txt').then(async (data) => {
  console.log(jschardet.detect(data));
})

这个方法会返回一个对象:encodingconfidenceencoding 是检测的编码,confidence 是这个检测结果的置信度。

每个检测器都会根据它的分析给出一个置信度(Confidence Level),置信度最高的编码就会被选中。就像我们之前说的,因为很多编码很相似,所以这个检测并不是百分之百准确,但 chardet 设计得比较聪明,通常能给出一个比较靠谱的结果。

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

转换字符集编码

现在我们拿到了文件内容的字符编码,需要一个转换器将内容转换为 utf-8, 这时我们需要引入一个新的库 iconv-lite

iconv-lite 是一个用于 Node.js 的轻量级字符编码转换库。它允许你在 Node.js 应用程序中进行字符编码的转换和处理,特别是处理非 UTF-8 编码的数据。与其他类似的库相比,iconv-lite 更加轻便,因为它不依赖外部的 C 库或者原生模块,完全用纯 JavaScript 实现。

import iconv from 'iconv-lite';

await readFile('book/book1.txt').then(async (data) => {
  const { encoding } = jschardet.detect(data);
  console.log(iconv.decode(data, encoding));
})

通过以上代码,我们可以将文件内容正确地解码为 UTF-8 格式,并输出到控制台。

Node.js 修改文件字符集为了批量修改文件字符集的问题,我编写了一个脚本,自动化地将大量文件的编码格式转换为常用的

获取到转码内容的后,我们就可以遍历之前获取的文件列表,全部进行转码重新写入文件了,这个步骤很简单,不单独进行讲解了,可以直接参考下面的完整代码。

完整代码

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) => {
      // 获取读取的内容编码
      const charset = jschardet.detect(data)
      // 转换内容编码
      const fileContent = iconv.decode(data, charset.encoding || 'GB2312')
      // 重新写回文件
      await writeFile(file, fileContent, { encoding: 'utf-8' }).catch((err) => {
        console.log(file + '文件写入失败', err);
      });
    });
  }
  console.log('文件重写完成!');
});

结语

通过使用 Node.js 和一些实用的第三方库,我们可以快速有效地解决这个问题。希望这篇文章能够帮助你更好地理解文件编码转换,并应用到实际生活和工作中。

相关链接

转载自:https://juejin.cn/post/7402572475718615059
评论
请登录