0. 基础概念
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,使用了一个事件驱动、非阻塞式 I/O 模型,让 JavaScript 运行在服务端的开发平台。
代码初体验:
console.log("hello NodeJS")
// 1.进入到对应 js 文件的目录下
// 2.执行 node 1-hello.js
// 3.输出:hello NodeJS
1. Buffer
1.1 概念
Buffer 是一个类似于数组的对象,用于表示固定长度的字节序列。Buffer 本质是一段内存空间,专门用来处理二进制数据。
1.2 特点
- Buffer 大小固定且无法调整
- Buffer 性能较好,可以直接对计算机内存进行操作
- 每个元素的大小为 1 字节(byte)
1.3 使用
1.3.1 Buffer 的创建
Node.js 中创建 Buffer 的方式主要如下几种:
Buffer.alloc
// 创建了一个长度为 10 字节的 Buffer,相当于申请了 10 字节的内存空间,每个字节的值为 0
// 结果为 <Buffer 00 00 00 00 00 00 00 00 00 00>
let buf_1 = Buffer.alloc(10);
Buffer.allocUnsafe
// 创建了一个长度为 10 字节的 Buffer,Buffer 中可能存在旧的数据, 可能会影响执行结果,所以叫 unsafe
let buf_2 = Buffer.allocUnsafe(10);
Buffer.from
// 通过字符串创建 Buffer
let buf_3 = Buffer.from('hello');
// 通过数组创建 Buffer
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
1.3.2 Buffer 与字符串的转化
可以借助 toString 方法将 Buffer 转为字符串
// buffer 与字符串的转换
const buffer = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
// 默认使用 UTF-8 的编码格式
console.log(buffer.toString())
注意:toString 默认是按照 utf-8 编码方式进行转换的。
1.3.3 Buffer 的操作
Buffer 可以直接通过 [] 的方式对数据进行处理。
const buffer = Buffer.from('hello');
// 二进制:1101000
console.log(buffer[0].toString(2))
// 修改 buffer
buffer[0] = 95
console.log(buffer.toString())
// 溢出 如果修改的数值超过 255 ,则超过 8 位数据会被舍弃
const buffer = Buffer.from('hello')
// 会舍弃高位的数字,因为八位的二进制最高值为 255 0001 0110 1001 => 0110 1001
buffer[0] = 361
console.log(buffer)
// 中文 一个 utf-8 的字符 一般 占 3 个字节
const buffer = Buffer.from('你好')
console.log(buffer)
注意:
如果修改的数值超过255,则超过8位数据会被舍弃 一个 utf-8 的字符一般占3个字节
2. fs 模块
fs 全称为 file system,称之为文件系统,是 Node.js 中的内置模块,可以对计算机中的磁盘进行操作。
2.1 文件写入
文件写入就是将数据保存到文件中,有如下的 API
方法说明writeFile异步写入writeFileSync同步写入appendFile/appendFileSync追加写入createWriteStream流式写入
2.1.1 异步写入
语法: fs.writeFile(file, data, [options], callback)
参数说明:
- file:文件名
- data:待写入的数据
- options:选项设置 (可选)
- callback:写入回调
返回值: undefined
代码示例:
// 1.导入 fs 模块
const fs = require('fs')
// 2.写入文件
// writeFile 异步写入,四个参数:1.文件路径 2.写入内容 3.配置信息 4.回调函数
// 文件写入成功
fs.writeFile('./座右铭.txt', '封狼居胥,禅于姑衍,饮马瀚海', error => {
// errror 为 null就是写入成功
if (error) {
console.log('文件写入失败')
return;
}
console.log('文件写入成功')
});
2.1.2 同步写入
语法: fs.writeFileSync(file, data, [options]) 参数说明:
- file:文件名
- data:待写入的数据
- options:选项设置 (可选) 返回值: undefined 代码示例:
// 1.导入 fs 模块
const fs = require('fs')
// 2.写入文件
// 同步写入,没有回调函数
fs.writeFileSync('./座右铭.txt', '封狼居胥,禅于姑衍,饮马瀚海,燕石勒然')
Node.js 中的磁盘操作是由其他线程完成的,结果的处理有两种模式:
同步处理:JavaScript 主线程会等待其他线程的执行结果,然后再继续执行主线程的代码,效率较低
异步处理:JavaScript 主线程不会等待其他线程的执行结果,直接执行后续的主线程代码,效率较好
2.1.3 追加写入
appendFile 作用是在文件尾部追加内容,appendFile 语法与 writeFile 语法完全相同
语法:
- fs.appendFile(file, data, [options], callback)
- fs.appendFileSync(file, data, [options])
返回值: 二者都为 undefined
代码示例:
// 1.引入 fs 模块
const fs = require('fs');
const content = '\r\n但使龙城飞将在,不教胡马度阴山';
// fs.appendFile('./座右铭.txt', content, error => {
// // errror 为 null就是写入成功
// if (error) {
// console.log('文件追加写入失败')
// return;
// }
// console.log('文件追加写入成功');
// })
// 同步文件追加写入
// fs.appendFileSync('./座右铭.txt', content)
// 使用 writeFile 的方式追加文件写入
fs.writeFile('./座右铭.txt', content, {flag: 'a'}, error => {
if (error) {
console.log('文件追加写入失败')
return;
}
console.log('文件追加写入成功')
})
console.log('hello world')
2.1.4 流式写入
语法: fs.createWriteStream(path, [options])
参数说明:
- path:文件路径
- options:选项配置( 可选 )
返回值: Object
代码示例:
// 1.导入 fs 模块
const fs = require('fs');
// 2.创建写入流对象
const writeStream = fs.createWriteStream('./观书有感.txt');
// 3.写入内容
writeStream.write('半亩方塘一鉴开\r\n')
writeStream.write('天光云影共徘徊\r\n')
writeStream.write('问渠那得清如许\r\n')
writeStream.write('为有源头活水来\r\n')
// 4.关闭通道 不是必须
// writeStream.close();
程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数。
流式写入方式适用于大文件写入或者频繁写入的场景, writeFile 适合于写入频率较低的场景。
2.2 文件读取
文件读取顾名思义,就是通过程序从文件中取出其中的数据,有如下几种 API:
方法说明readFile异步读取readFileSync同步读取createReadStream流式读取
2.2.1 异步读取
语法: fs.readFile(path, [options], callback)
参数说明:
- path:文件路径
- options:选项配置
- callback:回调函数
返回值: undefined
代码示例:
// 1.引入 fs 模块
const fs = require('fs')
// 2.异步读取
fs.readFile('./座右铭.txt', (error, data) => {
if (error) {
console.log('文件读取错误')
return
}
console.log(data.toString())
})
2.2.2 同步读取
语法: fs.readFileSync(path, [options])
参数说明:
- path:文件路径
- options:选项配置
返回值: string | Buffer
代码示例:
// 1.引入 fs 模块
const fs = require('fs')
// 2.同步读取
let data = fs.readFileSync('./座右铭.txt');
console.log(data.toString())
2.2.3 流式读取
语法: fs.createReadStream(path, [options])
参数说明:
- path:文件路径
- options:选项配置(可选)
返回值:Object
代码示例:
// 1.导入 fs 模块
const fs = require('fs')
// 2.创建读取流对象
const rs = fs.createReadStream('./观书有感.txt');
// 3.绑定 data 事件
rs.on('data', chunk => {
// chunk:块儿、大块儿
console.log(chunk)
console.log(chunk.length)
console.log(chunk.toString())
})
// 4.结束事件(可选)
rs.on('end', () => {
console.log('文件读取完成')
})
2.3 文件移动与重命名
在 Node.js 中,可以使用 rename 或 renameSync 来移动或重命名文件或文件夹
语法:
- fs.rename(oldPath, newPath, callback)
- fs.renameSync(oldPath, newPath)
参数说明:
- oldPath:文件当前的路径
- newPath:文件新的路径
- callback:操作后的回调
代码示例:
// 1.导入 fs 模块
const fs = require('fs');
// 2.文件重命名
// fs.rename('./座右铭-2.txt', './西汉名将.txt', error => {
// if (error) {
// console.log('文件重命名失败')
// return ;
// }
// console.log('文件重命名成功')
// })
// 3.文件移动
// 文件夹如果不存在,会报错误 Error: ENOENT: no such file or directory
fs.rename('./西汉名将.txt', './文件/西汉名将.txt', error => {
if (error) {
console.log(error, '移动文件出错');
return ;
}
console.log('操作成功')
})
2.4 文件删除
在 Node.js 中,可以使用 unlink 或 unlinkSync 或 rm 或 rmSync 来删除文件
语法:
- fs.unlink(path, callback)
- fs.unlinkSync(path)
参数说明:
- path:文件路径
- callback:操作后的回调
代码示例:
// 1.引入 fs 模块
const fs = require('fs')
// 2.调用 unlink 方法
// unlinkSync:同步删除
// fs.unlink('./座右铭-3.txt', error => {
// if (error) {
// console.log('删除文件错误', error)
// return;
// }
// console.log('删除文件成功')
// })
// 3.调用 rm 方法
// rmSync:同步删除
fs.rm('./文件/西汉名将.txt', error => {
if (error) {
console.log('文件删除失败', error)
return;
}
console.log('文件删除成功')
})
2.5 文件夹操作
在 Node.js 中可以通过如下 API 对文件夹进行创建、读取、删除等操作
方法说明mkdir / mkdirSync创建文件夹readdir / readdirSync读取文件夹rmdir / rmdirSync删除文件夹
2.5.1 创建文件夹
在 Node.js 中,可以使用 mkdir 或 mkdirSync 来创建文件夹
语法:
- fs.mkdir(path, [options], callback)
- fs.mkdirSync(path, [options])
参数说明:
- path:文件夹路径
- options:选项配置(可选)
- callback:操作后的回调
示例代码:
// 1.引入 fs 模块
const fs = require('fs')
// 2.创建文件夹
// mkdir make:制作 directory:目录
fs.mkdir('./html', error => {
if (error) {
console.log('创建目录失败', error)
return;
}
console.log('创建目录成功')
})
// 3.递归创建文件夹
fs.mkdir('./a/b/c', {
recursive: true
}, error => {
if (error) {
console.log("递归创建文件夹失败", error)
return;
}
console.log('递归创建文件夹成功')
})
// 4.递归同步创建文件夹
fs.mkdirSync('./a/b/c', {recursive: true});
2.5.2 读取文件夹
在 Node.js 中,可以使用 readdir 或 readdirSync 来读取文件夹
语法:
- fs.readdir(path, [options], callback)
- fs.readdirSync(path, [options])
参数说明:
- path:文件夹路径
- options:选项配置(可选)
- callback:操作后的回调
示例代码:
// 1.引入 fs 模块
const fs = require('fs')
// 2.读取文件夹
// readdir read:读取 dir:directory 目录
fs.readdir('./', (error, data) => {
if (error) {
console.log('读取文件夹错误', error)
return;
}
// [
// '1-文件写入.js',
// '2-追加写入.js',
// '3-流式写入.js',
// '4-文件读取.js',
// '5-流式读取.js',
// '6-练习-文件复制.js',
// '7-文件重命名与移动.js',
// '8-删除文件.js',
// '9-文件夹操作.js',
// 'a',
// 'html',
// '座右铭.txt',
// '文件',
// '观书有感.txt'
// ]
console.log(data)
})
//同步读取
// let data = fs.readdirSync('./');
// console.log(data);
2.5.3 删除文件夹
在 Node.js 中,可以使用 rmdir 或 rmdirSync 来删除文件夹
语法:
- fs.rmdir(path, [options], callback)
- fs.rmdirSync(path, [options]) 参数说明:
- path:文件夹路径
- options:选项配置(可选)
- callback:操作后的回调
示例代码:
// 1.引入 fs 模块
const fs = require('fs')
// 2.删除文件夹
// fs.rmdir('./文件', error => {
// if (error) {
// console.log('删除文件夹失败', error)
// return;
// }
// console.log('删除文件夹成功')
// })
// 3.递归删除文件夹
// 递归删除文件夹失败 [Error: ENOTEMPTY: directory not empty, rmdir 'E:\JavaEE\frontend\nodejs-study\2-fs文件系统\a']
// 不推荐使用
// fs.rmdir('./a', {recursive: true}, error => {
// if (error) {
// console.log('递归删除文件夹失败', error)
// return ;
// }
// console.log('递归删除文件夹成功')
// })
// 推荐使用
fs.rm('./a', {recursive: true}, error => {
if (error) {
console.log('递归删除文件失败', error)
return;
}
console.log('递归删除文件成功')
})
//同步递归删除文件夹
fs.rmdirSync('./a', {recursive: true})
2.6 查看资源状态
在 Node.js 中,可以使用 stat 或 statSync 来查看资源的详细信息
语法:
- fs.stat(path, [options], callback)
- fs.statSync(path, [options])
参数说明:
- path:文件夹路径
- options:选项配置(可选)
- callback:操作后的回调
示例代码:
// 1.引入 fs 模块
const fs = require('fs')
// 2.stat 方法 status 的缩写:状态
fs.stat('./观书有感.txt', (error, data) => {
if (error) {
console.log('操作失败', error)
return;
}
// Stats {
// dev: 985301708,
// mode: 33206,
// nlink: 1,
// uid: 0,
// gid: 0,
// rdev: 0,
// blksize: 4096,
// ino: 281474979770305,
// size: 92,
// blocks: 0,
// atimeMs: 1684373309132.9426,
// mtimeMs: 1684289136772.1648,
// ctimeMs: 1684289136772.1648,
// birthtimeMs: 1684289136770.7136,
// atime: 2023 - 05 - 18 T01: 28: 29.133 Z,
// mtime: 2023 - 05 - 17 T02: 05: 36.772 Z,
// ctime: 2023 - 05 - 17 T02: 05: 36.772 Z,
// birthtime: 2023 - 05 - 17 T02: 05: 36.771 Z
// }
console.log(data)
console.log(data.isFile())
console.log(data.isDirectory())
})
// 3.同步获取状态
let data = fs.statSync('./观书有感.txt');
console.log(data)
console.log(data.isFile())
console.log(data.isDirectory())
结果值对象结构:
- size:文件体积
- birthtime:创建时间
- mtime:最后修改时间
- isFile:检测是否为文件
- isDirectory:检测是否为文件夹
2.7 相对路径问题
fs 模块对资源进行操作时,路径的写法有两种:
- 相对路径 ./座右铭.txt:当前目录下的座右铭.txt 座右铭.txt:等效于上面的写法 ../座右铭.txt:当前目录的上一级目录中的座右铭.txt
- 绝对路径 D:/Program Files:windows 系统下的绝对路径 /usr/bin:Linux 系统下的绝对路径
相对路径中所谓的当前目录,指的是命令行的工作目录,而并非是文件的所在目录。所以当命令行的工作目录与文件所在目录不一致时,会出现一些 BUG。
2.8 __dirname
__dirname 与 require 类似,都是 Node.js 环境中的 '全局' 变量 __dirname 保存着当前文件所在目录的绝对路径,可以使用 __dirname 与文件名拼接成绝对路径
代码示例:
let data = fs.readFileSync(__dirname + '/data.txt');
console.log(data);
使用 fs 模块的时候,尽量使用 __dirname 将路径转化为绝对路径,这样可以避免相对路径产生的 Bug
2.9 练习
实现文件复制的功能
代码示例:
/**
* 需求:
* 复制【座右铭.txt】
*/
// 1.引入 fs 模块
const fs = require('fs');
// 全局对象,即 global 对象的属性,无须声明即可访问。它用于描述当前 Node 进程状态的对象,提供了一个与操作系统的简单接口。
const process = require('process')
// 方式一:使用 readFile
// 2.读取文件
// let data = fs.readFileSync('./座右铭.txt');
// // 3.写入文件
// fs.writeFileSync('./座右铭-2.txt', data);
// // 查看系统耗费内存
// // rss: 19795968 字节
// console.log(process.memoryUsage())
// 方式二:使用流式操作
// 2.创建流式读取
let rs = fs.createReadStream('./座右铭.txt');
// 3.创建流式写入
let ws = fs.createWriteStream('./座右铭-3.txt');
// // 4.绑定 data 事件
// rs.on('data', chunk => {
// ws.write(chunk);
// })
// // 5.绑定 end 事件
// rs.on('end', () => {
// // rss: 20885504 字节 相比于同步的方式占用内存会比较小
// console.log(process.memoryUsage())
// })
// 4.使用 pipe(管道) 可直接复制
rs.pipe(ws)
3. path 模块
path 模块提供了操作路径的功能&#
版权归原作者 刘大本尊 所有, 如有侵权,请联系我们删除。