node.js整理 03文件操作-遍历目录和文本编码

遍历目录

递归算法

  • 遍历目录时一般使用递归算法,否则就难以编写出简洁的代码。

  • 递归算法与数学归纳法类似,通过不断缩小问题的规模来解决问题

function factorial(n) {
    if (n === 1) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}


// 使用递归算法编写的代码虽然简洁,但由于每递归一次就产生一次函数调用,在需要优先考虑性能时,需要把递归算法转换为循环算法,以减少函数调用次数。

遍历算法

  • 目录是一个树状结构,在遍历时一般使用深度优先+先序遍历算法。
  • 深度优先,意味着到达一个节点后,首先接着遍历子节点而不是邻居节点。
  • 先序遍历,意味着首次到达了某节点就算遍历完成,而不是最后一次返回某节点才算数。
  • 因此使用这种遍历方式时,下边这棵树的遍历顺序是A > B > D > E > C > F。
          A
         / \
        B   C
       / \   \
      D   E   F

同步遍历

function travel (dir, cb) {
  fs.readdirSync(dir).forEach(function (file) {
    var pathname = path.join(dir, file);
    if (fs.statSync(pathname).isDirectory()) {
      travel (pathname, callbakc);
    }  else {
      callback(pathname);
    }
  });
}
  • 该函数以某个目录作为遍历的起点。遇到一个子目录时,就先接着遍历子目录。遇到一个文件时,就把文件的绝对路径传给回调函数。回调函数拿到文件路径后,就可以做各种判断和处理。因此假设有以下目录:
- /home/user/
    - foo/
        x.js
    - bar/
        y.js
    z.css
  • 使用以下代码遍历该目录时,得到的输入如下。
travel('/home/user', function (pathname) {
    console.log(pathname);
});

------------------------
/home/user/foo/x.js
/home/user/bar/y.js
/home/user/z.css

异步遍历

  • 如果读取目录或读取文件状态时使用的是异步API,目录遍历函数实现起来会有些复杂,但原理完全相同
function travel(dir, callback, finish) {
    fs.readdir(dir, function (err, files) {
        (function next(i) {
            if (i < files.length) {
                var pathname = path.join(dir, files[i]);

                fs.stat(pathname, function (err, stats) {
                    if (stats.isDirectory()) {
                        travel(pathname, callback, function () {
                            next(i + 1);
                        });
                    } else {
                        callback(pathname, function () {
                            next(i + 1);
                        });
                    }
                });
            } else {
                finish && finish();
            }
        }(0));
    });
}

文本编码

  • 常用的文本编码有UTF8和GBK两种,并且UTF8文件还可能带有BOM。在读取不同编码的文本文件时,需要将文件内容转换为JS使用的UTF8编码字符串后才能正常处理。

BOM的移除

  • BOM用于标记一个文本文件使用Unicode编码,其本身是一个Unicode字符("\uFEFF"),位于文本文件头部
  • 在不同的Unicode编码下,BOM字符对应的二进制字节如下:
    Bytes      Encoding
----------------------------
    FE FF       UTF16BE
    FF FE       UTF16LE
    EF BB BF    UTF8
  • 因此,可以根据文本文件头几个字节等于啥来判断文件是否包含BOM,以及使用哪种Unicode编码。

  • BOM字符虽然起到了标记文件编码的作用,其本身却不属于文件内容的一部分,如果读取文本文件时不去掉BOM,在某些使用场景下就会有问题。

  • 例如我们把几个JS文件合并成一个文件后,如果文件中间含有BOM字符,就会导致浏览器JS语法错误。因此,使用NodeJS读取文本文件时,一般需要去掉BOM。

  • 以下代码实现了识别和去除UTF8 BOM的功能。

function readText(pathname) {
    var bin = fs.readFileSync(pathname);

    if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) {
        bin = bin.slice(3);
    }

    return bin.toString('utf-8');
}

GBK转UTF8

  • NodeJS支持在读取文本文件时,或者在Buffer转换为字符串时指定文本编码; 但是,GBK编码不在NodeJS自身支持范围内。
  • 一般我们借助iconv-lite这个三方包来转换编码。使用NPM下载该包后,可以按下边方式编写一个读取GBK文本文件的函数。
var iconv = require('iconv-lite');

function readGBKText(pathname) {
    var bin = fs.readFileSync(pathname);

    return iconv.decode(bin, 'gbk');
}

单字节编码

  • 无法预知需要读取的文件采用哪种编码,因此也就无法指定正确的编码

  • 首先,如果一个文本文件只包含英文字符,比如Hello World,那无论用GBK编码或是UTF8编码读取这个文件都是没问题的。这是因为在这些编码下,ASCII0~128范围内字符都使用相同的单字节编码。

  • 反过来讲,即使一个文本文件中有中文等字符,如果需要处理的字符仅在ASCII0~128范围内,比如除了注释和字符串以外的JS代码,就可以统一使用单字节编码来读取文件,不用关心文件的实际编码是GBK还是UTF8。

1. GBK编码源文件内容:
    var foo = '中文';
2. 对应字节:
    76 61 72 20 66 6F 6F 20 3D 20 27 D6 D0 CE C4 27 3B
3. 使用单字节编码读取后得到的内容:
    var foo = '{乱码}{乱码}{乱码}{乱码}';
4. 替换内容:
    var bar = '{乱码}{乱码}{乱码}{乱码}';
5. 使用单字节编码保存后对应字节:
    76 61 72 20 62 61 72 20 3D 20 27 D6 D0 CE C4 27 3B
6. 使用GBK编码读取后得到内容:
    var bar = '中文';
  • 这里的诀窍在于,不管大于0xEF的单个字节在单字节编码下被解析成什么乱码字符,使用同样的单字节编码保存这些乱码字符时,背后对应的字节保持不变。

  • NodeJS中自带了一种binary编码可以用来实现这个方法

function replace(pathname) {
    var str = fs.readFileSync(pathname, 'binary');
    str = str.replace('foo', 'bar');
    fs.writeFileSync(pathname, str, 'binary');
}

转载于:https://www.cnblogs.com/jinkspeng/p/4395575.html

03-28
### MCP API 的文档与使用教程 MCP 是一种用于增强大型语言模型 (LLM) 功能的技术框架,它通过提示(Prompts)、资源(Resources)以及工具(Tools)这三种核心原语来扩展 LLM 能力[^2]。Apifox 平台也认识到 MCP 技术在 API 开发领域的重要作用,并将其应用于实际场景中[^1]。 为了实现将 `/Users/syw/project/wechatAr` 文件夹下的所有文件上传至远程服务器 `47.93.xx.xx` 用户名 `root` 下的 `/opt/ll` 目录的操作,可以基于 MCP 工具功能构建一个自定义的服务逻辑。以下是具体实现方法: #### 实现方案 利用 SCP 命令完成文件传输任务,并结合 MCP 的 Tool 功能封装此操作以便于后续调用。当关键词为“上传微信目录”时,触发该工具执行相应动作。 ```python import subprocess def upload_wechat_directory(): source_dir = "/Users/syw/project/wechatAr/*" target_server = "root@47.93.xx.xx:/opt/ll/" try: result = subprocess.run(["scp", "-r", source_dir, target_server], check=True) return {"status": "success", "message": f"All files from {source_dir} have been uploaded to {target_server}"} except Exception as e: return {"status": "error", "message": str(e)} # 将上述函数注册为 MCP 中的一个 tool tools = { "upload_wechat_directory_tool": upload_wechat_directory, } # 定义 prompt 和 resource 配置部分省略... ``` 以上代码片段展示了如何创建一个名为 `upload_wechat_directory_tool` 的工具并将其集成到 MCP 系统里去[^3]。每当接收到匹配条件的消息比如含有特定关键字的时候就会激活对应的行为即启动SCP进程从而达成目标需求。 #### 进一步学习资料推荐 对于希望深入研究或者实践更多关于 MCP 应用案例的人士来说,《MCP 教程进阶篇》提供了丰富的实例分析和技术细节值得参考阅读;另外《MCP 极简入门:超快速上手运行简单的 MCP 服务和 MCP 客户端》同样是非常好的起点材料之一可以帮助初学者迅速掌握基础概念及其运作机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值