Note.js 笔记
一、Buffer(缓冲区)
在 JavaScript 中,字符串是以 UTF-16 编码存储的,而不是字节流(如 ASCII 或 UTF-8)。对于需要处理二进制数据的操作(比如读取文件、从网络接收数据等),JavaScript 原生并没有内建的数据结构来直接处理这些原始数据。Buffer 就是为了解决这个问题而诞生的,它允许在内存中操作原始的二进制数据。
1.1、特点
原始二进制数据存储:Buffer 不是以字符的形式存储数据,而是直接以字节的形式存储数据。
固定大小:一旦创建,Buffer 的大小是固定的,不能动态增大或缩小。
直接访问内存:Buffer 提供了直接访问内存的能力,因此操作效率高。
1.2、创建Buffer
Buffer.from():从现有的字符串、数组或其他 Buffer 创建一个新的 Buffer。
const buf1 = Buffer.from('hello', 'utf-8'); // 创建一个包含字符串 "hello" 的 Buffer,<Buffer 68 65 6c 6c 6f>
const buf2 = Buffer.from([1, 2, 3, 4]); // 从数组创建 Buffer,<Buffer 01 02 03 04>
Buffer.alloc():分配一个指定大小的 Buffer,并填充为零。
const buf = Buffer.alloc(10); // 创建一个大小为 10 字节的 Buffer,初始化为零
Buffer.allocUnsafe():分配一个指定大小的 Buffer,但不初始化。该方法返回一个未初始化的 Buffer,操作速度更快,但需要==小心使用==,因为它可能包含之前的内存数据。
const buf = Buffer.allocUnsafe(10); // 创建一个大小为 10 字节的未初始化 Buffer
1.3、常见的 Buffer 方法
buf.toString([encoding], [start], [end]):将 Buffer 转换为字符串。可以指定编码格式(如 'utf-8'、'ascii'、'hex' 等)。
const buf = Buffer.from('hello');
console.log(buf.toString()); // 输出 'hello'
console.log(buf.toString('hex')); // 输出 '68656c6c6f'
buf.length:返回 Buffer 的字节长度。
const buf = Buffer.from('hello');
console.log(buf.length); // 输出 5
buf.write(string, [offset], [length], [encoding]):将字符串写入 Buffer 中,从指定的偏移位置开始,支持指定编码格式。
const buf = Buffer.alloc(10);
buf.write('hello');
console.log(buf); // 输出 <Buffer 68 65 6c 6c 6f 00 00 00 00 00>
buf.slice([start], [end]):从 Buffer 中截取指定范围的子 Buffer。
const buf = Buffer.from('hello');
const subBuf = buf.slice(1, 4);
console.log(subBuf.toString()); // 输出 'ell'
1.4、Buffer 与字符串的转换
Buffer 可以与字符串进行互相转换,支持多种编码格式。最常用的编码格式是 utf-8、ascii 和 hex。
从 Buffer 转换为字符串
const buf = Buffer.from('hello', 'utf-8');
console.log(buf.toString('utf-8')); // 输出 'hello'
从字符串转换为 Buffer
const buf = Buffer.from('hello', 'utf-8');
console.log(buf); // 输出 <Buffer 68 65 6c 6c 6f>
用途
处理文件 I/O:在 Node.js 中,文件读取和写入通常涉及二进制数据。Buffer 使得可以高效地读取和写入原始数据(如图片、音频、视频等)。
网络通信:许多网络协议(如 HTTP)使用二进制数据流。Buffer 允许 Node.js 高效地处理这些数据。
加密:加密算法通常需要处理二进制数据,Buffer 提供了适合加密操作的数据格式。
流处理:处理大量数据时,Buffer 在流(Stream)操作中扮演着重要角色,因为它可以在内存中以字节流的形式传输数据。
二、fs模块
fs(File System)模块是一个内置模块,用于与文件系统进行交互。它允许你在服务器端执行文件的读、写、删除、重命名等操作。fs 模块提供了同步和异步的 API,可以用来处理文件和目录。
在开始之前请先导入 fs
模块:const fs = require('fs');
2.1、写入文件
异步写:
fs.writeFile('./fileName.txt','hello world',(err)=>{
if(err){ console.log(err); return; }
console.log('文件写入成功!!');
})
同步写:
fs.writeFileSync('./fileName.txt','hello world!!');
2.2、读取文件
异步读:
fs.readFile('./fileName.txt', 'utf8', (err,data) => {
if (err) { console.log(err); return; }
console.log(data);
})
同步读:
const data = fs.readFileSync('./fileName.txt', 'utf8');
console.log(data);
2.3、追加字符
异步写:
fs.appendFile('./fileName.txt','\nhello java!','utf8',(err)=>{
if(err){ console.log(err); return; }
console.log('追加成功!');
})
同步写:
fs.appendFileSync('./fileName.txt','\nHello Python!','utf8');
2.4、删除文件
异步删:
fs.unlink('./fileName.txt',(err) => {
if(err){ console.log(err); return}
console.log('文件删除成功!');
})
同步删:
fs.unlinkSync('./fileName.txt');
2.5、重命名文件
异步重命名:
fs.rename('./fileName.txt', './fileNameNEW.txt',(err)=>{
if(err){ console.log(err); return; }
console.log('重命名成功!');
})
同步重命名:
fs.renameSync('./fileNameNEW.txt','./fileName.txt');
2.6、检查文件/目录是否存在
异步检查:
fs.access('./fileName.txt', fs.constants.F_OK, (err) => {
if (err) {
console.log('文件或目录不存在!');
} else {
console.log('文件或目录存在!');
}
});
同步检查01:
try {
fs.accessSync('./fileName.txt')
console.log('文件或目录存在!');
} catch (err) {
console.log('文件或目录不存在!');
}
同步检查02:
if(fs.existsSync('./fileName.txt')){
console.log('文件或目录存在!');
}else {
console.log('文件或目录不存在!');
}
2.7、创建目录
异步创建:
fs.mkdir('./新目录/a/b',{recursive:true},(err)=>{
if (err) throw err;
console.log('创建成功!');
})
同步创建:
fs.mkdirSync('./新目录/c/s',{recursive:true});
2.8、删除目录
异步删除:
// 旧版使用 rmdir
fs.rm('./新目录',{recursive:true},(err) => {
if (err) throw err;
console.log('删除成功!');
})
同步删除:
fs.rmSync('./新目录',{recursive:true});
2.9、读取目录内容
异步读目录:
fs.readdir('./新目录', (err, data) => {
if (err) throw err;
console.log(data);
})
同步读目录:
const dir = fs.readdirSync('../');
console.log(dir);
2.10、文件状态信息
异步:
fs.stat('./sss', (err, stats) => {
if (err) {
console.error('Error:', err);
} else {
console.log(stats.isDirectory()); // true: 如果路径是目录
console.log(stats.isFile()); // true: 如果路径是文件
}
});
同步:
try {
const dir = fs.statSync('./新目录');
console.log(dir.isDirectory()); // true: 如果路径是目录
console.log(dir.isFile()); // false: 如果路径是文件
}catch (err) {
console.error('Error:', err);
}
三、使用流(Stream)
3.1、Readable Stream(可读流)
导包:
const fs = require('fs');
创建一个可读流
const rs = fs.createReadStream('./abc.txt', { encoding: 'utf8' });
监听 'data' 事件,逐块读取文件内容
rs.on('data',(chunk) => {
console.log('chunk:', chunk);
})
监听 'end' 事件,文件读取完毕
rs.on('end', () => {
console.log('文件读取完毕');
});
fs.createReadStream(path):用于创建可读流。
data 事件:每次读取到数据块时触发。
end 事件:数据读取完成时触发。
3.2、Writable Stream(可写流)
Writable 流用于向文件或网络发送数据。
导包:
const fs = require('fs');
创建一个可写流:
const ws = fs.createWriteStream('output.txt', { encoding: 'utf8' });
使用 write() 方法写入数据:
ws.write('Hello, world!\n');
ws.write('This is a test.\n');
结束写入:
ws.end(() => {
console.log('数据写入完毕');
});
3.3、Duplex Stream(双工流)
导包:
const fs = require('fs');
const net = require('net');
创建一个 TCP 客户端(即双工流)
const client = net.createConnection({ port: 8080 }, () => {
console.log('连接到服务器');
client.write('Hello, Server!');
});
client.on('data', (data) => {
console.log('收到来自服务器的数据:', data.toString());
client.end(); // 结束连接
});
client.on('end', () => {
console.log('连接关闭');
});