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');
}
node.js整理 03文件操作-遍历目录和文本编码的更多相关文章
- node.js整理 02文件操作-常用API
NodeJS不仅能做网络编程,而且能够操作文件. 拷贝 小文件拷贝 var fs = require('fs'); function copy(src, dst) { fs.writeFileSync ...
- node.js整理 04网络操作
简介 var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content- ...
- 使用Node.JS监听文件夹变化
使用Node.JS监听文件夹改变有许多应用场合,比如: 构建自动编绎工具 当源文件改变时,自动运行build过程,比如当你写CoffeeScript文件或SASS CSS文件时,保存之后可即时生成对应 ...
- Linux基础(10)AIO项目设计与POSIX文件操作和目录管理
实现fast-cp :拷贝文件到目标对象 Linux的七种文件类型 :https://blog.csdn.net/linkvivi/article/details/79834143 ls -al :h ...
- node.js 学习03
node.js学习03 解决浏览器接收服务端信息之后乱码的问题: 服务器通过设置http响应报文头,告诉浏览器使用相应的编码 来解析网页. res.setHeader('Content','text/ ...
- node.js编译less文件
大多数文章对于到底怎样编译less文件并没有一个详细的说明,清一色的grunt命令,看得也是晕晕的,所以也就有了这篇手记的存在. 步入正题 1.安装配置好sublime text3(包括各种实用插件) ...
- node 学习笔记 - fs 文件操作
本文同步自我的个人博客:http://www.52cik.com/2015/12/03/learn-node-fs.html 最近看到群里不少大神都开始玩 node 了,我感觉跟他们步伐越来越大了, ...
- Node基础篇(文件操作)
文件操作 相关模块 Node内核提供了很多与文件操作相关的模块,每个模块都提供了一些最基本的操作API,在NPM中也有社区提供的功能包 fs: 基础的文件操作 API path: 提供和路径相关的操作 ...
- Node.js入门:文件查找机制
文件查找流程图 从文件模块缓存中加载 尽管原生模块与文件模块的优先级不同,但是都不会优先于从文件模块的缓存中加载已经存在的模块. 从原生模块加载 原生模块的优先级仅次于文件模块缓存的优 ...
随机推荐
- 【STL】 set集合容器常用用法
set集合容器:实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值:另外,还 ...
- php面向对象加载类、常用设计模式
加载类: include("./Ren.class.php"); include "./Ren.class.php"; 用此方法的时候include后面要加空格 ...
- 数据库的日志数据库(_log.ldf)文件太大,如何压缩
DUMP TRANSACTION TCB WITH NO_LOGBACKUP LOG TCB WITH NO_LOGDBCC SHRINKDATABASE(TCB) 执行这三条语句就可以了,这里的TC ...
- Intel Code Challenge Elimination Round (Div.1 + Div.2, combined)(set容器里count函数以及加强for循环)
题目链接:http://codeforces.com/contest/722/problem/D 1 #include <bits/stdc++.h> #include <iostr ...
- 报错 - Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lex failed with exit code 1
这里有两种情况:第一种是某xxx.m文件不存在或路径不对,而且里面有5.1什么的解决方法如下:在Build Phases-->Complie Sources中找到有两个xxx.m文件,一个正常, ...
- NYOJ题目112指数运算
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAs0AAAIICAIAAAAaCETRAAAgAElEQVR4nO3drW7jWtwv4PcmwnMhxb ...
- Sublime Text 无法使用Package Control的解决方法 以及 常用的插件安装过程
大概一个月之前给 Macbook air 装 Sublime Text 3 的时候,遇到过这个问题,当时解决了,现在回想,感觉忘的七七八八了,赶紧趁着还没有全忘光的时候记下来,当时的过程记得不一定准确 ...
- 网络中文乱码问题 utf-8
// 网络中文乱码问题 utf-8 [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- Delphi中的基础数据类型
参考http://www.cnblogs.com/del/archive/2007/12/04/982167.html 在学习之初,在这么多的数据类型中,最好记住这五种标准数据类型(整型.实型.字符型 ...
- ckplayer视频播放插件使用
研究ckplayer插件播放视频,播放视频需要配置信息修改如下: 1.设置ckplayer.js中的logo: 'null' 可以隐藏视频播放头部的图标: 2.设置ckplayer.js中的ckcpt ...