nodejs学习(二)Buffer、fs
一、 Buffer(缓冲区)
1. JavaScript 语言没有读取或操作二进制数据流的机制。 2. Node.js 中引入了 Buffer 类型使我们可以操作 TCP流 或 文件流。 3. Buffer 类型的对象类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被创建时确定,且无法调整。( buf.length 是固定的,不允许修改 ) 4. Buffer 是全局的,所以使用的时候无需 require() 的方式来加载
1.Buffer的操作
• 使用Buffer保存字符串 let str = "你好"; let buf = Buffer.from(str , "utf-8"); • 创建指定大小的Buffer对象 let buf3 = Buffer.alloc(1024*8)
2.Buffer的转换
• Buffer与字符串间的转换 – 支持的编码: • ASCII、 UTF-8、 UTF-16LE/UCS-2、 Base64、Binary、 Hex – 字符串转Buffer • Buffer.from(str , [encoding]); – Buffer转字符串 • buf.toString([encoding] , [start] , [end]);
3.写入操作
• 向缓冲区中写入字符串
– buf.write(string[, offset[, length]][, encoding])
• 替换指定索引位置的数据
– buf[index]
• 将指定值填入到缓冲区的指定位置
– buf.fill(value[, offset[, end]][, encoding])
4.读取操作
• 将缓冲区中的内容,转换为一个字符串返回
– buf.toString([encoding[, start[, end]]])
• 读取缓冲区指定索引的内容
– buf[index]
5.其他操作
• 复制缓冲区
– buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
• 对缓冲区切片
– buf.slice([start[, end]])
• 拼接缓冲区
– Buffer.concat(list[, totalLength])
二、fs(文件系统)
• 在Node中,与文件系统的交互是非常重要的,服务器的本质就将本地的文件发送给远程的客户端
• Node通过fs模块来和文件系统进行交互
• 该模块提供了一些标准文件访问API来打开、读取、写入文件,以及与其互。
• 要使用fs模块,首先需要对其进行加载
– const fs = require("fs");
1.同步和异步调用
• fs模块中所有的操作都有两种形式可供选择同步和异步。
• 同步文件系统会阻塞程序的执行,也就是除非操作完毕,否则不会向下执行代码。
• 异步文件系统不会阻塞程序的执行,而是
在操作完成时,通过回调函数将结果返回。
2.打开和关闭文件
• 打开文件
– fs.open(path, flags[, mode], callback)
– fs.openSync(path, flags[, mode])
• 关闭文件
– fs.close(fd, callback)
– fs.closeSync(fd)
3.打开状态
模式 说明 r 读取文件 , 文件不存在则出现异常 r+ 读写文件 , 文件不存在则出现异常 rs 在同步模式下打开文件用于读取 rs+ 在同步模式下打开文件用于读写 w 打开文件用于写操作 , 如果不存在则创建,如果存在则截断 wx 打开文件用于写操作, 如果存在则打开失败 w+ 打开文件用于读写, 如果不存在则创建, 如果存在则截断 wx+ 打开文件用于读写, 如果存在则打开失败 a 打开文件用于追加, 如果不存在则创建 ax 打开文件用于追加, 如果路径存在则失败 a+ 打开文件进行读取和追加, 如果不存在则创建该文件 ax+ 打开文件进行读取和追加,如果路径存在则失败
4.写入文件
• fs中提供了四种不同的方式将数据写入文件
– 简单文件写入
– 同步文件写入
– 异步文件写入
– 流式文件写入
1.简单文件写入
• fs.writeFile(file, data[, options], callback) • fs.writeFileSync(file, data[, options]) • 参数: – file 文件路径 – data 被写入的内容,可以是String或Buffer – options 对象,包含属性(encoding、 mode、flag) – callback 回调函数 //注意: - 该操作采用异步执行 - 如果文件已经存在则替换掉 - 默认写入的文件编码为utf8 - 回调函数有1个参数:err,表示在写入文件的操作过程中是否出错了。 - 如果出错了`err != null`,否则 `err === null`
demo:
/* fs.writeFile(file, data[, options], callback) fs.writeFileSync(file, data[, options]) file <string> | <Buffer> | <URL> | <integer> 文件名或文件描述符/要操作的文件路径 data <string> | <Buffer> | <TypedArray> | <DataView> | <Object> 要写入的数据 options <Object> | <string> 选项,可以对写入进行一些设置 encoding <string> | <null> 默认值: 'utf8' mode <integer> 默认值: 0o666 flag <string> 请参阅对文件系统 flags 的支持。 默认值: 'w'。 callback <Function> err <Error> | <AggregateError> **/ //导入文件模块 var fs = require("fs"); //创建要写入的信息 var msg = "hello world! 你好,世界!"; var msg1 = "第二次写入会不会覆盖第一次的呢?" //参数分别是文件路径,要写入的信息,编码,回调函数,回调函数需要有一个参数err //这种是覆盖写入,文件不存在则新建文件后写入,文件存在则覆盖写入 fs.writeFile("./test.txt", msg1, "utf8", function (err) { console.log("+++++++++++++++++++++" + err + "============") if (err) { console.log("写入文件出错,详细信息" + err) throw err; } else { console.log("写入文件成功") } } )
2.同步文件写入
• fs.writeSync(fd, buffer, offset, length[, position])
• fs.writeSync(fd, data[, position[, encoding]])
• 要完成同步写入文件,先需要通过openSync()打开文件来获取
一个文件描述符,然后在通过writeSync()写入文件。
• 参数
– fd 文件描述符,通过openSync()获取
– data 要写入的数据(String 或 Buffer)
– offset buffer写入的偏移量
– length 写入的长度
– position 写入的起始位置
– encoding 写入编码
demo:
/* 手动操作文件的步骤 1.打开文件: fs.openSync(path[, flags[, mode]]) - path 要打开文件的路径 - flags 打开文件要操作的类型:默认为r r:只读 w:可写的 - mode 设置文件的操作权限,一般不传(默认可读可写) 2.向文件中写入内容 fs.writeSync(fd, string[, position[, encoding]]) - fd 文件描述符 - string <string> | <Object> 要写入的内容被 - position <integer> 写入的其实位置 - encoding <string> 编码 返回: <number> 写入的字节数。 如果 string 是普通的对象,则它必须具有自有的(不是继承的)toString 函数属性。 3.保存关闭文件 fs.closeSync(fd) fd <integer>关闭文件描述符。 返回 undefined。 */ var fs = require("fs"); //w模式会覆盖写入 var fd = fs.openSync("test.txt", "w"); console.log("描述符:" + fd); var length = fs.writeSync(fd, "这是同步写入的内容"); console.log("写入的长度:" + length); fs.closeSync(fd);
3.异步文件写入
• fs.write(fd, buffer, offset, length[, position], callback)
• fs.write(fd, data[, position[, encoding]], callback)
• 要使用异步写入文件,先需要通过open()打开文件,然后在回
调函数中通过write()写入。
• 参数:
– fd 文件描述符
– data 要写入的数据(String 或 Buffer)
– offset buffer写入的偏移量
– length 写入的长度
– position 写入的起始位置
– encoding 写入编码
demo
/* 手动操作文件的步骤 1。异步打开文件: fs.open(path[, flags[, mode]], callback) - path 要打开文件的路径 - flags 打开文件要操作的类型:默认为r r:只读 w:可写的 - mode 设置文件的操作权限,一般不传(默认可读可写) - callback 回调有两个参数 (err, fd)。 err:错误对象,如果没有则为null fd:文件描述符 返回值:该方法会返回一个文件描述符作为结果,我们可以通过该操作符来文件进行各种操作 fs.write(fd, buffer[, offset[, length[, position]]], callback) 用来异步写入一个文件 fs.close(fd[, callback]) -用来关闭文件 */ var fs = require("fs"); fs.open("异步test.txt", "w", function (err, fd) { //判断是否出错 if (!err) { fs.write(fd, "这是异步写入内容", function (err) { if (!err) { console.log("写入成功"); fs.close(fd, function (err) { if (!err) { console.log("文件关闭成功"); } else { console.log("文件关闭失败"); } }) } else { console.log("写入失败"); } }) } }); console.log("这个应该比异步的先执行完,对吧?")
4.流式文件写入
• 往一个文件中写入大量数据时,最好的方法之一 是使用流。 • 若要将数据异步传送到文件,首需要使用以下语 法创建一个Writable对象: – fs.createWriteStream(path[, options]) • path 文件路径 • options {encoding:"",mode:"",flag:""} • 一旦你打开了Writable文件流,就可以使用 write()方法来写入它,写入完成后,在调用end() 方法来关闭流。
demo
//流式写入 //创建可写流 /* fs.createWriteStream(path[, options]) - 可以用来创建一个可写流 - path :文件路径 - options 配置参数 */ var fs = require("fs"); var ws = fs.createWriteStream("writerstream.txt"); //可以通过监听流的打开和关闭事件来监听流的打开和关闭 /* on(时间字符,回调函数) -可以为对象绑定一个事件 once(事件字符串,回调函数) - 可以为对象绑定一个一次性事件,该事件会将在出发一次后自动回滚失效 */ ws.once("open", function () { console.log("六打开了"); }) ws.on("close", function () { console.log("流关闭了"); }) //通过ws像文件输入内容 ws.write("第一次输入"); ws.write("第二次输入"); ws.write("第三次输入"); //关闭流 ws.end()
5.读取文件
• fs中提供了四种读取文件的方式
– 简单文件读取
– 同步文件读取
– 异步文件读取
– 流式文件读取
1.简单文件读取
• fs.readFile(file[, options], callback) • fs.readFileSync(file[, options]) – 参数: • file 文件路径或文件描述符 • options <Object> | <String> – encoding <String> | <Null> 默认 = null – flag <String> 默认 = 'r' • callback 回调函数,有两个参数err 、 data
err 错误对象
data 返回一个buffer,要转成字符串需要data.tostring
demo1
var fs = require('fs'); fs.readFile("./test.txt", "utf-8", function (err, data) { console.log("data:" + data); console.log("err:" + err); if (err) { console.log("读取文件出错了:错误是" + err) } else { console.log("读取文件成功,以下为内容:") console.log(data) //当option的编码没有指定,返回的是一个buffer // console.log(data.toString()) } })
demo2:读取并写入零一个文件
var fs = require('fs'); fs.readFile("C:\\Users\\tjp40922\\Desktop\\a.png", function (err, data) { console.log("err:" + err); if (err) { console.log("读取文件出错了:错误是" + err) } else { console.log("读取文件成功") fs.writeFile("copy.png",data,function (err) { if (!err){ console.log("写入成功") }else { console.log("写入失败。。,原因是:"); console.log(err) } }) } })
2.同步文件读取
• fs.readSync(fd, buffer, offset, length,
position)
– 参数:
• fd 文件描述符
• buffer 读取文件的缓冲区
• offset buffer的开始写入的位置
• length 要读取的字节数
• position 开始读取文件的位置
3.异步文件读取
• fs.read(fd, buffer, offset, length,
position, callback)
– 参数:
• fd 文件描述符
• buffer 读取文件的缓冲区
• offset buffer的开始写入的位置
• length 要读取的字节数
• position 开始读取文件的位置
• callback 回调函数 参数err , bytesRead , buffer
4.流式文件读取
• 从一个文件中读取大量的数据时,最好的方法之一就是流式读取,这样将把一个文件作为Readable流的形式打开。
• 要从异步从文件传输数据,首先需要通过以下语法创建一个Readable流对象: – fs.createReadStream(path[, options]) • path 文件路径 • options {encoding:"",mode:"",flag:""}
• 当你打开Readable文件流以后,可以通过readable事件和read()请求,或通过data事件处理程序轻松地从它读出。
demo1
var fs = require("fs"); //创建一个可读流 var rs = fs.createReadStream("writerstream.txt"); //监听流的开启和关闭 rs.once("open", function () { console.log("可读流打开了"); }) rs.on("close", function () { console.log("可读流关闭了"); }) //如果要读取一个刻度流中的数据,必须为可读流绑定一个data事件,data事件绑定完毕,他会自动开始读取数据 rs.on("data",function (data) { console.log(data.toString()) })
demo2:从一个流到另一个流
var fs = require("fs"); //创建一个可读流 var rs = fs.createReadStream("writerstream.txt"); var ws = fs.createWriteStream("tttt.txtt"); //监听流的开启和关闭 rs.once("open", function () { console.log("可读流打开了"); }) rs.on("close", function () { console.log("可读流关闭了"); // 在可读流关闭后也要关闭可写流 ws.end(); }) ws.once("open", function () { console.log("可写流打开了"); }) ws.on("close", function () { console.log("可写流关闭了"); }) //如果要读取一个刻度流中的数据,必须为可读流绑定一个data事件,data事件绑定完毕,他会自动开始读取数据 rs.on("data", function (data) { console.log(data.toString()) //把可读流的数据写入可写流 //这边要注意,不能再这里关闭可写流,要不然只会昔日如一次 ws.write(data); })
可以用更加简单的pipe
var fs = require("fs"); //创建一个可读流 var rs = fs.createReadStream("writerstream.txt"); var ws = fs.createWriteStream("xdxx.txtt"); rs.pipe(ws);
6.其他操作
• 删除目录
– fs.rmdir(path, callback)
– fs.rmdirSync(path)
• 重命名文件和目录
– fs.rename(oldPath, newPath, callback)
– fs.renameSync(oldPath, newPath)
• 监视文件更改写入
– fs.watchFile(filename[, options], listener)
注意:
1. 异步操作无法通过 try-catch 来捕获异常,要通过判断 error 来判断是否出错。
2. 同步操作可以通过 try-catch 来捕获异常。
3. 不要使用 `fs.exists(path, callback)` 来判断文件是否存在,直接判断 error 即可
4. 文件操作时的路径问题
- 在读写文件的时候 './' 表示的是当前执行node命令的那个路径,不是被执行的js文件的路径
- __dirname, 表示的永远是"当前被执行的js的目录"
- __filename, 表示的是"被执行的js的文件名(含路径)"
5. error-first 介绍(错误优先)