nodejs入门教程之文件系统fs(七)

在这里插入图片描述

学习背景

已知nodejs并非运行在浏览器中的,它可以直接访问电脑的文件系统,并进行文件的读取与写入。nodejs提供了一个访问文件系统的模块fs,它和我们之前学习的http、url、querystring一样,都是nodejs的核心模块,文件系统模块(fs)也是nodejs中常用的模块。所以掌握fs基础用法,对于我们后面的学习是不可或缺的。

学习目标

之前章节我们通过http、url、querystring实现了一个简单的web服务器,有注册登录、改名等功能。该章节我们学习fs的基本用法以及一些常用的方法,并通过这些常用的方法给我们的web服务器添加下载头像的功能。

fs简介

  • fs是nodejs内置核心模块
  • fs的底层是c++实现的,它是对c++代码封装
  • fs的方法均有同步和异步的版本,但是本章节主要是讲使用异步用法

同步与异步的区别

  • 同步方法都以Sync结尾,例如fs.readFileSync
  • 同步方法会阻塞线程,nodejs是单线程应用,所以阻塞线程是致命的。因此不建议用同步的方法来调用
  • 同步方法没有回调函数,异步有回调函数
  • 异步的方法性能更好速度更快

常用方法

  • 导入模块
const fs = require('fs')
  • fs.readFile(path[, options], callback) 读取文件
const fs = require('fs')

fs.readFile('/etc/passwd', (err, data) => {
  if (err) throw err;
  console.log(data);
});
  • fs.writeFile(file, data[, options], callback)写入文件
const fs = require('fs')

const data = new Uint8Array(Buffer.from('Hello Node.js'));
// ”Hello Node.js“写入message.text中 
fs.writeFile('message.txt', data, (err) => {
  if (err) throw err;
  console.log('The file has been saved!');
});
  • fs.createReadStream(path[, options]) 创建读取文件流

  • fs.createWriteStream(path[, options])创建写入文件流

    这个是创建输入输出流,关于流的介绍,看下一小结
    
const fs = require('fs')

//创建读取文件流
const readStream = fs.createReadStream(__dirname + '/files/1.txt')

//创建写入文件流
const writeStream = fs.createWriteStream(__dirname + '/files/2.txt')


//将读取文件流流向写入文件流完成文件写入
readStream.pipe(writeStream)

  • fs.copyFile(src, dest[, mode], callback) 拷贝文件
cons { copyFile, constants } = require('fs');

function callback(err) {
  if (err) throw err;
  console.log('source.txt was copied to destination.txt');
}

// 默认情况下将创建或覆盖 destination.txt。
copyFile('source.txt', 'destination.txt', callback);

// 通过使用 COPYFILE_EXCL,如果 destination.txt 存在,则该操作将失败。
copyFile('source.txt', 'destination.txt', constants.COPYFILE_EXCL, callback);

流Stream

什么是流呢,字面理解的话,是液体可以流动。nodejs流和普通流动的液体有共同特点。比如水管中的流水,通常是从一个地方流向另一个地方。nodejs中的流也可以这么理解,它是一种数据流,也是从一个地方流向另一个地方。通常是从输入流流向输出流,就像之前我们学到的fs.createReadStream就是创建读取流,把它想象是水的源头。fs.createWriteStream就是创建输出流,是水的流向的地方。而pipe方法就是把两个流之间接一个管道把数据从输入流流向输出流

1 、流的类型:

  • Readable - 可读的流 (例如 fs.createReadStream()).

  • Writable - 可写的流 (例如 fs.createWriteStream()).

  • Duplex - 可读写的流 (例如 net.Socket).

  • Transform - 在读写过程中可以修改和变换数据的 Duplex 流 (例如 zlib.createDeflate()).

2、流的事件监听:

// 监听流事件的方法
steam.on('close',()=>{
	console.log('close 事件被触发')
})
  • open事件 readStream被打开是触发
  • close 事件 流被关闭的时候触发
  • data 事件读取到数据的时候被触发,通常是多长触发
  • finish 调用 stream.end() 数据都已传输完成之后触发。
  • error 读写流的时候出错时触发

3、流常用方法:

  • readable.pipe(destination[, options]) 绑定可写流到可读流,将可读流自动切换到流动模式,并将可读流的所有数据推送到绑定的可写流。
    数据流会被自动管理,所以即使可读流更快,目标可写流也不会超负荷。

  • readable.pause() 暂停读取
    readable.pause() 方法使流动模式的流停止触发 'data' 事件,并切换出流动模式。 任何可用的数据都会保留在内部缓存中。

    const readable = getReadableStreamSomehow();
    readable.on('data', (chunk) => {
      console.log(`接收到 ${chunk.length} 字节的数据`);
      readable.pause();
      console.log('暂停一秒');
      setTimeout(() => {
    	console.log('数据重新开始流动');
    	readable.resume();
      }, 1000);
    });
    

    如果存在 'readable' 事件监听器,则 readable.pause() 方法不起作用。

  • readable.resume() 暂停恢复读取

    readable.resume() 方法将被暂停的可读流恢复触发 'data' 事件,并将流切换到流动模式。

    readable.resume() 方法可以用来充分消耗流中的数据,但无需实际处理任何数据:

    getReadableStreamSomehow()
      .resume()
      .on('end', () => {
    	console.log('到达流的尽头,但无需读取任何数据');
      });
    

    当存在 'readable' 事件监听器时,readable.resume() 方法不起作用。

  • readable.destroy([error]) 销毁
    销毁流。 可选地触发 'error' 事件,并触发 'close' 事件(除非将 emitClose 设置为 false)。 在此调用之后,可读流将会释放所有内部的资源,并且将会忽略对 push() 的后续调用。

    一旦调用 destroy(),则不会再执行任何其他操作,并且除了 _destroy() 以外的其他错误都不会作为 'error' 触发。

    实现者不应该重写此方法,而应该实现 readable._destroy()。

  • writable.destroy([error]) 销毁输出流。

4 流的案例

自己实现读写

const readStream = fs.createReadStream(__dirname + '/files/1.txt')

    //创建写入文件流
    const writeStream = fs.createWriteStream(__dirname + '/files/2.txt')

    readStream.on('data', (data) => {
        console.log('读取到了数据')
        writeStream.write(data)
    })

    writeStream.on('finish', () => {
        console.log('写入完毕')
    })
    readStream.on('end', () => {
        console.log('读取完毕')
        writeStream.end()
        writeStream.close()
        readStream.close()
    })

    readStream.on('error', (e) => {
        console.log('读取失败')
        console.log(e)
    })

    writeStream.on('error', (e) => {
        console.log('写入失败')
        console.log(e)
    })


使用pipe管道

		//创建读取文件流
    const readStream = fs.createReadStream(__dirname + '/files/1.txt')

    //创建写入文件流
    const writeStream = fs.createWriteStream(__dirname + '/files/2.txt')


    //将读取文件流流向写入文件流完成文件写入
    readStream.pipe(writeStream)

两个实现的功能是一样的,pipe可以理解为自己帮你实现读和写两部操作

实现下载头像

我们之前实现了简单的http服务器,也大概知道了请求request和response。现在要实现下载头像的功能,我们要知道response 其实是一个输出流,不过他不是文件输出流,他是网络输出流,我们返回的内容其实都是通过流把数据返回回去的。头像文件也是一样,把头像文件的数据写给response。

1、注册一个url路由,映射到getAvatar方法上

   switch (request.pathname) { // 根据解析出来的pathname链接到用户信息模块路由的对应参数上
            case '/register': //注册
                this.userRoute.register(request, res);
                break
            case '/login': //登录
                this.userRoute.login(request, res)
                break
            case '/changeNickname': //改昵称
                this.userRoute.changeNickname(request, res)
                break
            case '/getAvatar': // 获取头像
                this.userRoute.getAvatar(request, res)
                break
            default: // 其他路由
                this.userRoute.handelOther(request, res);
                break
        }

2、实现读取头像文件的方法

  getAvatar(req, res) {
	  
        const readStream = fs.createReadStream(path.join(__dirname, '../files/avatar.jpeg'))
		//先获取文件读取流,也就输入流, path是一个专门处理文件夹路径的模块
        res.writeHead(200, { 'Content-Type': 'image/jpeg' });
	   // 属于http协议中的内容,设置返回的内容类型
        readStream.pipe(res)
	  // 把文件读取流写入到响应流中
    }

3、请求http://localhost:8080/getAvatar 可以看到输出的头像内容

在这里插入图片描述

最后

根据这一章节学习我们应该掌握了fs文件系统,以及操作文件流的时候用到的stream的用法。并实现了把文件流接入http响应流中,实现图像下载。最后本章节涉及的代码比较多,你可以通过访问GITHUB代码仓库下载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TristanWong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值