Nodejs入门--fs模块全解

49 阅读8分钟

1.Nodejs入门

Cmd 指令

cls 清除当前终端操作记录 d: 切换路径 dir 查看当前文件夹列表 cd <路径> 切换路径

nodejs

  1. 顶级对象 global globalThis
  2. nodejs 之中可以使用的api setTimeOut console.log()

Buffer(缓冲器)

  1. 定义: JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。

但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。

  1. Buffer的创建
/* 1. buffer的创建 */

// alloc(分配) 返回一个指定大小的 Buffer 实例,如果没有设置 fill,则默认填满 0
let buf = Buffer.alloc(10)

// allocUnsafe 返回一个指定大小的 Buffer 实例,但是它不会被初始化,所以它可能包含敏感的数据
// 内存空间可以重复使用,allocUnsafe不会清空空间,会有遗留的缓存数据
let buf_2 = Buffer.allocUnsafe(10)

// from
// Buffer.from(array): 返回一个被 array 的值初始化的新的 Buffer 实例(传入的 array 的元素只能是数字,不然就会自动被 0 覆盖)
// Buffer.from(arrayBuffer[, byteOffset[, length]]): 返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer。
// Buffer.from(buffer): 复制传入的 Buffer 实例的数据,并返回一个新的 Buffer 实例
// Buffer.from(string[, encoding]): 返回一个被 string 的值初始化的新的 Buffer 实例
let buf_3 = Buffer.from('hellow')
console.log(buf_3)

  1. Buffer的读写
// buffer 与字符串的转换
let buf1 = Buffer.from([334, 455, 344, 444, 555,])
console.log(buf1.toString()) // 默认使用UTF-8的转换方式

// [] buffer对象的读取
let buf2 = Buffer.from("hellow")
// console.log(buf2[0].toString()) // 转换为二进制
console.log(buf2[0].toString());
buf2[0]=95
console.log(buf2[0].toString()) 

// 溢出
let buf3=Buffer.from('hellow')
buf3[0]=888; // 舍弃高位的数字
console.log(buf3[0].toString())

// 中文
let buf4 = Buffer.from("你好!")

fs模块

  1. fs写入文件
// 需求
// 新建一个txt文件,并且写入内容

// 1.导入fs模块
const fs = require('fs')

// 2.写入内容
// fs.writeFile(file,data,options(可选),callback)
fs.writeFile("./write.txt", "写入测试", res => {
    // res 失败:错误对象 成功:null
    if(res){
        console.log(res, '写入失败!');
        return;
    };
    console.log(res, '写入成功!');
})

  1. fs模块的异步与同步
const fs = require('fs')

/* 1.异步写入 */
fs.writeFile(file,data,options(可选),callback)
fs.writeFile("./write.txt", "写入测试", res => {
    // res 失败:错误对象 成功:null
    if(res){
        console.log(res, '写入失败!');
        return;
    };
    console.log(res, '写入成功!');
    console.log("异步回调代码");
})

console.log("同步代码")

/*2. 同步写入 */
fs.writeFileSync("./writeasync.txt", "写入测试")

  1. fs的追加写入
const fs = require('fs')

// 1.追加操作 appendFile
fs.appendFile("./write.txt","异步追加的内容!",err=>{
    if(err){
        console.log(err,"操作失败!");
    }
    console.log(err,"操作完成");
})

fs.appendFileSync("./write.txt","\r\n同步追加!")

// 2. 使用writeFile进行追加操作
// fs.writeFile() 是将目标文件里面的内容重写,并不会从原有的内容上添加
// 
fs.writeFile("./write.txt","love",{flag:"a"},()=>{})

  1. fs的流式写入
const ws = fs.createWriteStream(path.resolve(__dirname, 'test.txt'), {
  flags: 'w', // 写流不能用r,会报错.可以用'a'表示追加
  encoding: 'utf8', // 不写默认是utf8
  autoClose: true, // 写完是否自动关闭
  // start: 0, //从第几个字节开始写
  highWaterMark: 3 // 这是安全线,默认写的水位线是16k,即16 * 1024。表示总共写入的大小在这个范围内表示安全的,因为这代表着链表缓存区的大小,如果满了,那么就需要rs.pause()暂停读取,等缓存区的内容开始写入,留出一部分空间后,再去写入。如果超过这个值,虽然不会阻止你写入,但是会告诉你已经超了这条安全线了。特别注意:超过这个水位线也没事,只是超过会ws.write()会返回给你false,不超过返回的是true
})
const fs = require('fs')

// 1. 创建写入流对象
const ws=fs.createWriteStream('./write.txt')

// 2. 写入
ws.write("1111")
ws.write("2222")
ws.write("3333")
ws.write("4444")

// 3. 关闭通道
ws.close()

  1. fs模块的文件读取
const fs = require('fs')

// 1. readFile 异步读取
// @params (文件路径,配置项(选),回调)
fs.readFile("./write.txt",(err,data)=>{
    if(err){
        console.log("失败");
        return
    }
    console.log(data);// buffer 对象
    console.log(data.toString(),"异步");
})

// 2. readFileSync 同步读取
let resdata=fs.readFileSync("./write.txt")
console.log(resdata)
console.log(resdata.toString(),"同步")

  1. fs模块的流式读取

const fs = require("fs")

// 1. 创建文件读取对象
const rs = fs.createReadStream("./write.txt");

//监听流的开启和关闭
rs.once('open',function(){
    console.log('可读流打开了');
});
rs.once('close',function(){
    console.log('可读流关闭了');
});


// 2. 绑定data事件
// 进行流式读取
rs.on("data",(chunk)=>{
    console.log(chunk,'数据');
    console.log(chunk.toString(),'数据');
    console.log(chunk.length,'数据长度');
})

// 3. end
rs.on("end",()=>{
    console.log('读取完成');
})

  1. 复制文件
  • 方法1
//这里实现用两个流实现文件的复制
//fs6.js
//流式文件读取
/* 
    流式文件读取也适用于一些比较大的文件,可以分多次将文件读取到内存中
*/

var fs = require('fs');

//创建一个可读流、可写流
var rs = fs.createReadStream('7464.jpg');
var ws = fs.createWriteStream('复习题2.jpg');

//监听流的开启和关闭
rs.once('open',function(){
    console.log('可读流打开了');
});
rs.once('close',function(){
    console.log('可读流关闭了');
    ws.end();
});

ws.once('open',function(){
    console.log('可写流打开了');
});
ws.once('close',function(){
    console.log('可写流关闭了');
});

// 如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,data事件绑定完毕,它会自动开始读取数据
// 读取到的数据通过回调函数的参数返回,在这里我们定义一个参数data获取它
rs.on('data',function(data){
    ws.write(data);
});


  • 方法2

// 上面那种方式太麻烦了,这里用封装好的方法

// 导入模块
var fs = require('fs');

// 创建一个可读流、可写流
var rs = fs.createReadStream('7464.jpg');
var ws = fs.createWriteStream('复习题2.jpg');

// pipe()可以将可读流中的内容,直接输出到可写流中
rs.pipe(ws);


  1. fs模块重命名和移动

/* 文件重命名 和 移动 */

// 1. 导入fs模块
const fs = require("fs")

// 2. 调用rename 方法
fs.rename("./write-copy.txt","./write-rename.txt",err=>{
    if(err){
        console.log('操作失败 :>> ', err);
        return
    }
    console.log('操作成功 :>> ', '操作成功');
})

// 3. 文件的移动
fs.rename("./write-rename.txt","./pos/write-rename.txt",err=>{
    if(err){
        console.log('err :>> ', err);
        return
    }
    console.log('操作成功 :>> ', '操作成功');
})

// 4. rename的同步操作 renameSync (没有callback)

  1. fs模块的删除操作
/* 删除操作 */

// 1.导入
const fs = require("fs")

// 2. 调用unlink方法 ===》unlinkSync
fs.unlink("./write-copy2",err=>{
    if(err){
        console.log('err :>> ', err);
        return
    }
    console.log('操作成功 :>> ');
})

// 3. 使用rm方法 14.4 ====> rmSync

fs.rm("./writeasync.txt", err => {
    if (err) {
        console.log('err :>> ', err);
        return
    }
    console.log('操作成功 :>> ', '操作成功');
}
)

  1. fs模块操作文件夹
  • 创建文件夹
/* 文件夹的操作 */

// 1. 导入
const fs = require("fs")

// 2. 创建文件夹 mk (make) 制作 dir (directory) 文件夹
fs.mkdir("./test", err => {
    if (err) {
        console.log('err :>> ', err);
        return
    }
    console.log('C创建成功 :>> ');
})

// 2-2. 递归创建文件
// recursive options参数,表示是否递归创建
fs.mkdir("./A/B/C", { recursive: true } ,err => {
    if (err) {
        console.log('err :>> ', err);
        return
    }
    console.log('C创建成功 :>> ');
})


  • 读取文件夹
/* 文件夹的操作 */

// 1. 导入
const fs = require("fs")

// 2. 读取文件夹
fs.readdir("./A",(err,data)=>{
    if(err){
        console.log('err :>> ', err);
        return
    }
    console.log('资源 :>> ', data);  // ["B"]
})


  • 删除文件夹
/* 文件夹的操作 */

// 1. 导入
const fs = require("fs")

// 2. 删除文件夹
fs.rmdir("./test", err => {
    if (err) {
        console.log('err :>> ', err);
        return
    }
    console.log('删除成功 :>> ');
})

// 2-3 递归删除 (不建议使用)
// options递归操作
fs.rmdir("./A",{recursive:true}, err => {
    if (err) {
        console.log('err :>> ', err);
        return
    }
    console.log('删除成功 :>> ');
})

// 2.4 rm删除 (推荐使用)
fs.rm("./html",{recursive:true}, err => {
    if (err) {
        console.log('err :>> ', err);
        return
    }
    console.log('删除成功 :>> ');
})


  1. fs模块查看资源状态

// 1. 导入
const fs = require("fs")

// 2. stat方法 status缩写 ===》 statSync
fs.stat("./write.txt",(err,data)=>{
    if(err){
        console.log('err :>> ', err);
        return
    }
    console.log('data :>> ', data);
    /* 
    Status{
        信息。。。。
    }
    */

    // 判断文件类型
    console.log(data.isFile(),"是否是文件");
    console.log(data.isDirectory(),"是否是文件夹")

    /* 
    1.stats.isFile(): 如果是文件则返回true,否则返回false;
    2.stats.isDirectiory(): 如果是目录则返回true,否则返回false;
    3.stats.isBlockDevice(): 如果是块设备则返回true,否则返回false;
    4.stats.isCharacterDevice(): 如果是字符设备返回true,否则返回false;
    5.stats.isSymbolicLink(): 如果是软链接返回true,否则返回false;
    6.stats.isFIFO(): 如果是FIFO,则返回true,否则返回false.FIFO是UNIX中的一种特殊类型的命令管道;
    7.stats.isSocket(): 如果是Socket则返回true,否则返回false;
    8.stats.size(): 文件的大小(以字节为单位)。
    */
})

  1. fs路径
/* fs路径 */

// 1.导入
const fs = require("fs")

// 2. 相对路径
fs.writeFileSync("./path.txt","相对路径创建")
fs.writeFileSync("path1.txt","相对路径创建")
fs.writeFileSync("./css/path2.txt","相对路径创建")

// 3. 绝对路径
// 方法1 使用全路径带盘符,注意c盘的权限
fs.writeFileSync("C:/Users/mi/Desktop/FE/Nodejs/style/test.css","css")
// 方法2 不使用盘符,直接/开始,也默认以盘符开始
fs.writeFileSync("/Users/mi/Desktop/FE/Nodejs/style/test.txt","绝对路径")




13.fs路径bug + __dirname

/* fs路径--相对路径?? */

// 1.导入
const fs = require("fs")

// 2. 相对路径
/* 
  fs模块的相对路径参照物:命令行的工作目录
*/
fs.writeFileSync("./index.html","相对路径创建")

// 3. 绝对路径  解决相对路径fs模块工作问题
//  __dirname 保存的是文件所在目录的绝对路径
console.log("__dirname", __dirname)

fs.writeFileSync(__dirname + "/index.html", "相对路径创建")


  1. fs批量重命名文件
/* fs批量重命名 */

// 1.导入
const fs = require("fs")

// 2.获取文件
const testFiles = fs.readdirSync("./test")
console.log(testFiles);

// 3. 循环数组
testFiles.forEach((item, index) => {
    console.log(item, index);

    // 操作 - 重命名
    fs.rename(`./test/${item}`, `./test/${index + "-" + item}`,err=>{
        if(err){
            console.log('err :>> ', err);
            return
        }
        console.log("操作成功");
    })
});
  1. path模块
/* path模块 */

// 导入
const fs = require("fs")
const path = require("path")

/* 1. path.resolve() */
// 拼接规范的绝对路径
// let p=path.resolve(__dirname,"./path.txt")
let p = path.resolve(__dirname, "path.txt")
console.log(p);

/* 2. path.sep() */
// 获取操作系统的路径分割符
console.log(path.sep()) // win ==> \ linux==> /

/* 3. path.parse() */
// 解析路径并返回对象

/* 4. path.basename()*/
// 快速获取当前文件名

/* 5. path.dirname() */
// 获取路径的目录名

/* 6. path.extname() */
// 获取文件的扩展名