006 I/O模块fs
[a] fs文件系统
在node中,与文件系统的交互时非常重要的,服务器的本质就是将本地的文件发送给远程的客户
node通过fs模块实现与文件的交互
fs是node中的核心模块(内部模块)
fs系统最主要的操作就是文件的读取和写入
[B] 同步和异步
1. fs中所有的操作都有两种形式:同步和异步;异步的版本中函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。
2. 同步文件会阻塞程序的运行,也就是除非文件操作完毕,否则不会执行下面的程序
3. 异步文件不会阻塞程序的运行,而是在操作完成时通过回调函数返回。
4. 建议大家使用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。
菜鸟教程学习:https://www.runoob.com/nodejs/nodejs-tutorial.html
异步文件:
全部读取:readFile 全部写入:writeFile
部分读取:read 部分写入:write
同步文件:
全部读取:readFileSync 全部写入:writeFileSync
部分读取:readSync 部分写入:writeSync
1. fs.read() 读取文件部分内容(根据参数而定)
语法
fs.read(fd, buffer, offset, length, position, callback)
参数:
fd - 通过 fs.open() 方法返回的文件描述符。
buffer - 数据写入的缓冲区。
offset - 缓冲区写入的写入偏移量。
length - 要从文件中读取的字节数。
position - 文件读取的起始位置,如果 position 的值为 null,则会从当前文件指针的位置读取。
callback - 回调函数,有三个参数err, bytesRead, buffer, err 为错误信息, bytesRead 表示读取的字节数,buffer 为缓冲区对象。
【注】:
使用fs.read()方法读取文件内容时,首先需要一个文件描述符fd,fs.read()方法可以实现部分文件内容的读取。
通过length和position参数可以指定读取文件内容的长度和读取内容的起始位置。
2. fs.readFile() 读取文件全部内容
语法:
fs.readFile(filename[, options], callback)
参数:
filename —— 表示要读取的文件
callback —— 回调函数有2个参数 (err, data),参数 data 是文件的内容。如果没有指定参数encoding, 则返回值为Buffer。
【注】:
fs.readFile()方法能且只能读取文件的全部内容,通过设置编码方式可以以字符串或Buffer的形式返回读结果。
3. fs.read()和fs.readFile()方法的比较
本质上讲,fs.readFile()方法是对fs.read()方法的进一步封装,fs.readFile()方法可以方便的读取文件的全部内容。
相比fs.readFile()方法,使用fs.read()方法读取文件的全部内容可操作性要强很多。首先要用fs.stat判断文件的大小,然后使用fs.open()创建文件描述符,最后再使用fs.read()方法读取文件内容。
// 导入fs模块
var fs = require("fs");
1.同步文件写入
// 1. 打开文件 var fd = fs.openSync("./Nodejs/filesystem/hello.txt", "w") // 2. 向文件中写入内容 fs.writeSync(fd, "今天天气不错欸,我们去爬山吧~~~~", 5); // 3. 关闭文件 fs.closeSync(fd);
2. 异步文件写入
// 1. 打开文件 fs.open("./Nodejs/filesystem/hello.txt", "w", function(err, fd){ if(err){ return console.log(err); } // 2. 向文件中写入内容 fs.write(fd, "今天天气不错欸,我们去爬山吧~~~~", function(err){ if(!err){ console.log("文件写入成功!"); } }); // 3. 关闭文件 fs.close(fd,function(er){ if(!er){ console.log("文件成功关闭~~~"); } }); })
writeFile函数介绍:
fs.writeFile(fd, data, [option,] callback)
第一个参数:fd,文件名或文件描述符(结合fs.open)
第二个参数:data, 要写入文件的数据,可以是 String(字符串) 或 Buffer(缓冲) 对象
第三个参数:默认为:{encoding, mode, flag},一般只修改flag => {encoding:"utf8", mode:0666, flag:"a"}
第四个参数:回调函数,callback(err),err包含写入失败时的错误信息
【注】
1. 直接打开文件默认是 w 模式,所以如果文件存在,该方法写入的内容会覆盖旧的文件内容。
2. 该方法一般用在fs.open方法内部
异步写入:
fs.open("./Nodejs/input.txt", "w", function(err, fd){ if(err){ return console.error(err); } for(var i = 0; i <= 3; i++){ fs.writeFile("./Nodejs/input.txt", `我是${i}个学生\n`, {encoding:"utf8", mode:0666, flag:"a"}, function(e){ if(e){ return console.log(e); } }) console.log("ok") } })
等价于:
var fs = require("fs"); fs.writeFile("./Nodejs/filesystem/hello_1.txt", "这是简单文件的写入", function(err){ if(err){ return err; }else{ console.log("文件写入成功~~") } })
同步写入:
var fd = fs.openSync('./simpleSync.txt', 'w') fs.writeFileSync(fd, '我是简单文件同步第一句!\n', function(err){ if(err){ console.log(err) return } console.log('写入文件成功!') })
等价于
var fs = require("fs"); fs.writeFileSync("./Nodejs/filesystem/hello_1.txt", "这是简单文件的写入");
// 流式文件写入 var fs = require("fs"); // 1. 创建一个写入文件流 var ws = fs.createWriteStream("./Nodejs/filesystem/hel_2.txt"); // 创建时间监听流的打开和关闭 ws.once("open", function(){ console.log("流打开了~~~"); }) ws.once("close", function(){ console.log("流关闭了~~~"); }) // 2. 向文件中写入数据, 以ws.end(); ws.write("我是熊大~\n"); ws.write("我是熊二~\n"); ws.write("我是熊三~\n"); ws.write("我是熊四~\n"); ws.end();
[D] 文件的读取
1. 同步文件的读取
2. 异步文件的读取
3. 简单文件的读取
同步读取
示例:
// 简单文件的同步读取 var fs = require("fs"); var rd = fs.readFileSync("./Nodejs/filesystem/input.txt"); console.log(rd.toString());
异步读取:
示例:
// 简单文件的异步读取 var fs = require("fs"); var rd = fs.readFile("./Nodejs/filesystem/input.txt", function(err,rd){ if(err){ return err; } console.log(rd.toString()); });
4. 流式文件读取
示例:
var fs = require("fs"); // 1. 创建读取文件流 var rs = fs.createReadStream("./Nodejs/filesystem/timg.jpg"); // 2. 创建读取流的打开和关闭监听事件 rs.once("open", function(){ console.log("流打开了~~"); }) rs.once("close", function(){ console.log("流关闭了~~"); }) // 3. 如果要读取一个可读流的数据,必须为这个可读流绑定一个data事件,data事件绑定完毕,他会自动读取数据 // 每次读取的文件dt长度为65536 rs.on("data", function(dt){ console.log(dt); }) // 简易写法 var fs = require("fs"); // 1. 创建一个可读流 var rd = fs.createReadStream("./Nodejs/filesystem/timg.jpg"); // 创建一个可写流 var ws = fs.createWriteStream("./Nodejs/filesystem/mn.jpg"); rd.pipe(ws);
[E] Stream(流)
1. 简介
Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。
2. 所有的 Stream 对象都是 EventEmitter 的实例
常用的事件有:
data - 当有数据可读时触发。
end - 没有更多的数据可读时触发。
error - 在接收和写入过程中发生错误时触发。
finish - 所有数据已被写入到底层系统时触发。
3. 读取流 —— createReadStream
1. 创建一个可读流
var rs = fs.createReadStream('./input.txt')
2. 设置字符编码
rs.setEncoding('UTF8');
3. 创建流打开和关闭时的监听事件
语法:
rs.once('open', callback)
rs.once('close', callback)
4. 添加监听事件 - 在读取过程中的不同阶段添加自定义操作
语法:
rs.on(status, callback)
参数:
status: 读取过程中的状态
data - 当有数据可读时触发。
end - 没有更多的数据可读时触发。
error - 在接收和写入过程中发生错误时触发。
finish - 所有数据已被写入到底层系统时触发。
callback: 回调函数
即在指定状态时出发的事件
4. 写入流 —— createWriteStream
1. 创建一个写入流
var ws = fs.createWriteStream('./outtxt.txt')
2. 写入内容并设置写入时的字符集
ws.write(txt, 'utf-8')
3. 标记文件末尾
ws.end()
4. 添加监听事件
// 写入文件结束后调用 ws.on('finish', () => { console.log('写入文件结束~~~') })
// 写入文件报错时调用
writerStream.on('error', (err) => {
console.log(err);
});
5. 管道流 —— pipe
管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中
通常用于复制文件,或部分复制文件
1. 创建一个可读流
var rs = fs.createReadStream('input.txt');
2. 创建一个可写流
var ws = fs.createWriteStream('output.txt');
3. 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中 rs.pipe(ws);
6. 链式流 —— pipe
链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。
1. 示例
// 压缩 input.txt 文件为 input.txt.gz fs.createReadStream('input.txt') .pipe(zlib.createGzip()) .pipe(fs.createWriteStream('input.txt.gz'));
注:
zlib需要先导入
var zlib = require('zlib');
2. 则上述的文件复制工作可简化为一个链式流
fs.createReadStream('./inputStream.txt').pipe(fs.createWriteStream('./outtxt.txt'))
[F] 获取文件信息 —— stat
1. 语法
fs.stat(path, callback)
参数说明:
path - 文件路径。
callback - 回调函数,带有两个参数如:(err, stats), stats 是 fs.Stats 对象。
stats类中的方法有:
stats.isFile() 如果是文件返回 true,否则返回 false。
stats.isDirectory() 如果是目录返回 true,否则返回 false。
stats.isBlockDevice() 如果是块设备返回 true,否则返回 false。
stats.isCharacterDevice() 如果是字符设备返回 true,否则返回 false。
stats.isSymbolicLink() 如果是软链接返回 true,否则返回 false。
stats.isFIFO() 如果是FIFO,返回true,否则返回 false。FIFO是UNIX中的一种特殊类型的命令管道。
stats.isSocket() 如果是 Socket 返回 true,否则返回 false。
2. 示例:
var fs = require('fs'); fs.stat('./data.js', function (err, stats) { if(err){ console.log(err) return } console.log(stats.isFile()); //true })
[G] 删除文件 —— unlink
1. 语法
fs.unlink(path, callback)
参数说明:
path - 文件路径。
callback - 回调函数,没有参数。
2. 示例代码
fs.unlink('./data.js', (err) => { if(err){ console.log(err) console.log('删除文件失败~~~') return } console.log('删除文件成功~~~') })
[H] 创建目录 —— mkdir
1. 语法
fs.mkdir(path[, options], callback)
参数说明:
path - 文件路径。
options 参数可以是:
recursive - 是否以递归的方式创建目录,默认为 false。
mode - 设置目录权限,默认为 0777。
callback - 回调函数,没有参数。
2. 示例
fs.mkdir('./Carrey', (err) => { if(err){ console.log(err) console.log('创建文件夹失败了~~~') return } console.log('创建文件夹成功~~~') })
[ I ]读取目录 —— readdir
1. 语法
fs.readdir(path, callback)
参数使用说明如下:
path - 文件路径。
callback - 回调函数,回调函数带有两个参数err, files,err 为错误信息,files 为 目录下的文件数组列表。
2. 示例
fs.readdir('./Carrey', (err, files) => { if(err){ console.log(err) console.log('读取文件失败了~~~') return } console.log(files) })
[J] 删除目录 —— rmdir
1. 语法
fs.rmdir(path, callback)
参数使用说明如下:
path - 文件路径。
callback - 回调函数,没有参数。
注:
该方法只能删除空的目录,当目录内部不为空时,会报错
2. 示例
fs.rmdir('./Carrey', (err) => { if(err){ console.log(err) console.log('删除目录失败~~~') return } console.log('删除目录成功~~~') })