nodejs学习(二)Buffer、fs
一、 Buffer(缓冲区)
? 从结构上看Buffer非常像一个数组,它的元素为16进制的两位数。
? 实际上一个元素就表示内存中的一个字节。
? 实际上Buffer中的内存不是通过JavaScript分配的,而是在底层通过C++申请的。
? 也就是我们可以直接通过Buffer来创建内存中的空间。
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 回调函数
demo:
/*
fs.writeFile(file, data[, options], callback)
fs.writeFileSync(file, data[, options])
file | | | 文件名或文件描述符/要操作的文件路径
data | | | |
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 | 要写入的内容被
- position 写入的其实位置
- encoding 编码
返回: 写入的字节数。
如果 string 是普通的对象,则它必须具有自有的(不是继承的)toString 函数属性。
3.保存关闭文件
fs.closeSync(fd)
fd 关闭文件描述符。 返回 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| – encoding | 默认 = null – flag 默认 = '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)