当前位置: 首页 > article >正文

NodeJs / Bun 分析文件编码 并将 各种编码格式 转为 另一个编码格式 ( 比如: GB2312→UTF-8, UTF-8→GB2312)

版本号

"iconv-lite": "^0.6.3",
"chardet": "^2.0.0",

github.com/runk/node-chardet
可以识别文本是 哪种编码
( 大文件截取一部分进行分析,速度比较快 )

let bun_file_obj = Bun.file(full_file_path)
let file_bytes = await bun_file_obj.bytes()

// 截取
let slice_end_index = file_bytes.length > 300 ? 300 : file_bytes.length
let type_arr = chardet.analyse(file_bytes.slice(0, slice_end_index))

// 取第一个结果, 可信度高
let type = type_arr[0]
console.log(full_file_path + "___" + type.name + "___" + type?.lang);

github.com/ashtuchkin/iconv-lite
支持所有的编码类型的转换 !!!

iconv.decode(…)

将任意编码的文本转为 JavaScript 字符串,
参数 Buffer, 返回值 string
如果编码写错, 会导致 乱码+乱码, 彻底废了.
解析之前可以用 chardet 识别一下编码格式
大文件建议截取一部分进行分析,速度比较快
提前知道编码,就不需要它了,

iconv.encode(…)

将 JavaScript 字符串转为另一个编码
参数 string, 返回值 Buffer
比如 GB2312

let data = iconv.encode("哈哈哈", "GB2312");
fs.writeFileSync("./test.txt", data);

更多用法到 iconv-lite README 里看

代码

NodeJs 的 fs.readFile 回调类型就是 Buffer,可直接用,

Bun 有两个方法
bun_file_obj.bytes() 返回类型是 Uint8Array
( 可以用, 但 TypeScript 类型会报错, Buffer 继承自 Uint8Array, 防止源码中用了 Buffer 特有的 api .建议转一下类型 )
bun_file_obj.arrayBuffer() 返回类型是 ArrayBuffer

两个都不可以直接用,
所以先用 Buffer.from(...) 将这两个类型转为 Buffer,

完整代码

import fs from 'node:fs';
import iconv from 'iconv-lite';
import path from 'node:path';
import chardet from 'chardet';

let dir_path = "D:\\Desktop\\新建文件夹2\\新建文件夹"
// 读取文件夹中所有文件名
let file_name_list = fs.readdirSync(dir_path)

convert_dir_files()

// ( 
//   循环中,一定要用 let 定义变量, 
//   如果用 var, 由于回调函数不是立即执行,
//   读取变量时,已经不是当时的值
// )
async function convert_dir_files() {
    for (const item of file_name_list) {

        // 拼接完整的路径
        let full_file_path = path.resolve(dir_path, item)

        // Bun 官方首推的 文件IO 方式, 用起来更舒服
        let bun_file_obj = Bun.file(full_file_path)

        // 读取文件 ( Uint8Array )
        let file_bytes = await bun_file_obj.bytes()

        // 分析编码 ( 截取一小段 提高性能 )
        let slice_end_index = file_bytes.length > 300 ? 300 : file_bytes.length
        let type_arr = chardet.analyse(file_bytes.slice(0, slice_end_index))
        let type = type_arr[0]

        // 只处理 GB2312
        if (type.name == "GB18030" && type?.lang == "zh") {
            
            let file_buffer = Buffer.from(file_bytes)
            // 将 GB2312 解码 为 JavaScript 字符串类型 (js默认编码是 utf16)
            let de_file_data = iconv.decode(file_buffer, 'GB2312').toString();
            // 写入文件 ( bun_file_obj.type 默认就是 utf8 编码, 比 utf16 更省空间)
            await bun_file_obj.write(de_file_data)
            
            // 如果要继续操作此文件, write 一定要 await,
            // 因为在写入文件时,文件禁止被其他操作,比如下面的 rename 就会报错

        } else if (type.name == "UTF-8") {
            // 不做任何处理
        } else {
            console.log("未知编码:" + "___" + item + "___" + type.name + "___" + type?.lang);
        }

        // 处理一下文件名
        let new_file_path = path
            .resolve(
                dir_path,
                item
                    .replace(/[\t\r\f\n\s]*/g, "")
            )

        // 如果 2 次文件名不同,就重命名
        if (full_file_path != new_file_path) {
            // 重命名
            fs.rename(full_file_path, new_file_path, (err) => {
                if (err) throw err;
            })
        }

    }
}

检查编码

Bun 执行
byte 进行截取后, 100 个 10M 的文件, 可以在瞬间分析完毕

import fs from 'node:fs';
import path from 'node:path';
import chardet from 'chardet';

let dir_path = "D:\\Desktop\\新建文件夹2\\新建文件夹"
let dir1_path = "D:\\Desktop\\新建文件夹2\\utf8"
let dir2_path = "D:\\Desktop\\新建文件夹2\\gb2312"

if (!fs.existsSync(dir1_path)) {
    fs.mkdirSync(dir1_path)
}

if (!fs.existsSync(dir2_path)) {
    fs.mkdirSync(dir2_path)
}

// 读取文件夹中所有文件名
let file_name_list = fs.readdirSync(dir_path)

for (const item of file_name_list) {
    let full_file_path = path.resolve(dir_path, item)
    let bun_file_obj = Bun.file(full_file_path)
    
    // 读取文件
    let file_bytes = await bun_file_obj.bytes()
    
    // 截取一定长度的数据, 进行分析, 文件太大影响分析速度
    let slice_end_index = file_bytes.length > 300 ? 300 : file_bytes.length
    let type_arr = chardet.analyse(file_bytes.slice(0, slice_end_index))
    
    // 取第一个结果, 可信度高
    let type = type_arr[0]
    console.log(item + "___" + type.name + "___" + type?.lang);
    
    // 移动文件
    if (type.name == "UTF-8") {
    
        fs.renameSync(full_file_path, path.resolve(dir1_path, item))
        
    } else if (type.name == "GB18030" && type?.lang == "zh") {
        
        fs.renameSync(full_file_path, path.resolve(dir2_path, item))
        
    } else {
        // 其他类型不移动
    }
}

http://www.kler.cn/a/523754.html

相关文章:

  • DeepSeek-R1本地部署笔记
  • 万物皆有联系:驼鸟和布什
  • Charles 4.6.7 浏览器网络调试指南:流量过滤与分析(六)
  • C语言自定义数据类型详解(二)——结构体类型(下)
  • git困扰的问题
  • 文本左右对齐
  • 【论文推荐|深度学习,滑坡检测,多光谱影像,自然灾害,遥感】2022年Landslide4Sense竞赛成果:基于多源卫星影像的先进滑坡检测算法研究(五)
  • 【某大厂一面】数组和链表区别
  • MATLAB绘图:动态波浪图
  • lwIP——4 网络接口
  • [MySQL]事务的隔离级别原理与底层实现
  • 2.策略模式(Strategy)
  • 如何使用Git进行版本控制?
  • 单细胞分析基础-第一节 数据质控、降维聚类
  • NLP自然语言处理通识
  • 前端25.1.26学习记录
  • IDM-VTON本地部署教程:双重编码 + 文字提示,解锁真实野外试穿
  • 【Elasticsearch】 索引模板 ignore_missing_component_templates
  • 【自学嵌入式(6)天气时钟:软硬件准备、串口模块开发】
  • 一文大白话讲清楚webpack进阶——5——dev-server原理及其作用
  • 【信息系统项目管理师-选择真题】2010上半年综合知识答案和详解
  • java求职学习day15
  • dokploy 如何部署 nuxt 项目?(进来少踩坑)
  • 【uniapp】uniapp使用java线程池
  • 1.1 画质算法的主要任务
  • AI软件栈:LLVM分析(二)