fs 模块学习笔记
使用场景:
- 对文件进行处理的底层方法,如读取文件内容,处理目录等;
- fs 模块不能很好的处理对于图片等二进制文件的处理,可以使用 Buffer 模块或者 Stream 模块。
如果你没有以上需求,请略过此部分以节约你的时间。
tags:
对文件内容处理:readFile() writeFile()
对文件本身处理:
1. 对文件内容进行处理
readFile() —— 读取文件内容
作用: 读取文件的内容
示例代码:(异步方法)
新建文件 test.txt,内容如下:
this is a test file.
新建文件 readFile.js,内容如下:
var fs = require("fs"); // 异步读取 fs.readFile('test.txt', function (err, data) { if (err) { return console.error(err); } console.log("data: ", data); console.log("异步读取 data.toString(): ", data.toString()); }); console.log("程序执行完毕。");
打印结果:
程序执行完毕。 data: <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74 20 66 69 6c 65 2e> 异步读取 data.toString(): this is a test file.
结论:
readFile() 第二个参数回调函数的参数 data 是一个 Buffer 类型的值,这一点从打印结果可以看出,可以使用 toString() 转换为我们想要的字符串类型的值;
使用 readFile() 可以读取 .doc .exe 等你能想到的文件,但是考虑文件过大时一次性读取文件内容到内存中有可能出现爆内存的情况,大文件建议使用 Stream 流进行处理。
补充:
同步的写法
var fs = require("fs"); // 同步读取 var data = fs.readFileSync('test.txt'); console.log("data: ", data); console.log("同步读取 data.toString(): ", data.toString()); console.log("程序执行完毕。");
打印结果:
data: <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74 20 66 69 6c 65 2e> 同步读取 data.toString(): this is a test file. 程序执行完毕。
结论:
同步的写法就是在原方法名后面加上 Sync,如:readFile() 变为 readFileSync();
同步方法没有第二个参数的回调函数,取而代之的是直接返回值,值通常为异步函数第二个回调函数中提供的值,如同步方法返回值 data 就是异步写法第二个参数回调函数的参数值;
文件操作大多有同步和异步方法,异步性能高,同步用于处理特定情形,掌握同步方法与异步方法的规律,下面将只介绍异步方法,同步方法按照上述规律进行总结。
writeFile() —— 写入文件内容
作用: 读取文件内容
示例代码:
新建文件 test.txt,内容如下:
this is a test file.
现在的目的是往 target.js 文件中写入 test.txt 的内容
var fs = require("fs"); fs.readFile('test.txt', function (err, data) { if (err) { console.error(err); } console.log("准备写入文件"); fs.writeFile('target.js', data.toString(), function(err) { if (err) { return console.error(err); } console.log("数据写入成功!"); }); });
结果:
在会当前目录中发现自动新建 target.js 文件,并且内容为 test.txt 的内容。
结论:
- 思路:先读取文件 test.txt 的内容 data,在将 data.toString() 写入 target.js 中;
writeFile() 的参数:
- 第一个参数为要写入到哪里,直接填写文件名为写入到当前目录下,没有该文件会自动创建该文件,有该文件会替换该文件;也可以写一个路径;
- 第二个参数为写入的内容,可以是字符串,也可以是这里从其它文件读取的内容 data.toString();
- 第三个参数是个回调函数,主要判断这个过程有没有错误;
- 以上示例代码相当于小文件复制的 demo。
2. 对文件本身进行处理
做个有趣的试验
打开一个浏览器(前端都用谷歌无争议吧),按 F12 打开控制台
在控制台中连续输入以下代码:
document.write('Hello World') undefined document.write('Hello World') undefined
可以看到浏览中打印了两次 "Hello World",但是如果现在我不想要它追加,而是重新打印内容,要如何操作呢?
在控制台中输入以下代码:
document.open() document.write('Hello World'); undefined document.write('Hello World'); undefined document.close() undefined document.write('Hello World'); undefined
可以看到在 open() 和 close() 之间输入了两次 "Hello World",在 close() 方法之后再次输入 "Hello World" 会替代之前的内容。
总结:
良好的习惯应该是这样的:操作之前先打开一个浏览器的"画布",然后可以在里面天马行空的"描绘",等操作完成后还要记得关闭这个"画布",这算一个完整的流程,不会与其它操作进行互串。
同样的,对于文件的处理也提供了类似的机制。
3. 对目录进行处理
mkdir() —— 创建目录
作用: 创建目录
参数:
- 第一个参数为要创建目录的路径名;
- 第二个参数为回调函数,判断是否出错。
示例代码:
var fs = require("fs");
console.log("创建目录 /tmp/test/");
fs.mkdir("/tmp/test/",function(err){
if (err) {
return console.error(err);
}
console.log("目录创建成功。");
});
- 打印结果:
{ Error: ENOENT: no such file or directory, mkdir 'D:\tmp\test'
at Error (native)
errno: -4058,
code: 'ENOENT',
syscall: 'mkdir',
path: 'D:\\tmp\\test' }
结论:
- 当前目录下没有 tmp 目录,所以创建 tmp\test\ 时会因为 tmp 目录还没创建而报错,node 创建目录只能一层一层的创建;
- mkdir() 也不能创建已存在的目录,否则也会保存
Error: EEXIST: file already exists
;
readdir() —— 查询目录
作用:查看指定目录的子级包含哪些子目录或子文件
参数:
- 第一个参数为要查看的那个目录路径;
- 第二个参数为回调函数,其中参数 files 为查看指定目录下有哪些子目录或子文件,是个数组,可以通过 forEach 遍历查看。
示例代码:
var fs = require("fs"); console.log("查看 /tmp 目录"); fs.readdir("/tmp/",function(err, files){ if (err) { return console.error(err); } files.forEach( function (file){ console.log( file ); }); });
打印结果:
查看 /tmp 目录 test
rmdir() —— 删除目录
作用: 删除指定目录
参数:
- 第一个参数为要删除的目录路径,如 tem/test 只会删除 test 目录,是不会删除 tmp 目录的;
- 第二个参数为回调函数,判断是会否删除出错。
示例代码:
var fs = require("fs"); // 执行前创建一个空的 /tmp/test 目录 console.log("准备删除目录 /tmp/test"); fs.rmdir("/tmp/test",function(err){ if (err) { return console.error(err); } console.log("读取 /tmp 目录"); fs.readdir("/tmp/",function(err, files){ if (err) { return console.error(err); } files.forEach( function (file){ console.log( file ); }); }); });
打印结果:
准备删除目录 /tmp/test 读取 /tmp 目录