我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Nodejs中可写流write的实现方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Nodejs中可写流write的实现方法

本篇内容主要讲解“Nodejs中可写流write的实现方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Nodejs中可写流write的实现方法”吧!

可写流-Writable

fs.createWriteStream调用例子

  • 首次读取的数据会真实写入目标文件

  • 其余次读取的数据要根据读取数据是否超出highWaterMark ,是的话存入缓存区等待写入目标文件中

const fs = require("fs");
const path = require("path");
const bPath = path.join(__dirname, "b.txt");
let ws = fs.createWriteStream(bPath, {
  flags: "w",
  encoding: "utf-8",
  autoClose: true,
  start: 0,
  highWaterMark: 3,
});
ws.on("open", function (fd) {
  console.log("open", fd);
});
ws.on("close", function () {
  console.log("close");
});
 //string 或者buffer,ws.write 还有一个boolea的返回值
ws.write("1");
//flag 表示 当前要写的值是直接是否直接写入文件,不能超出了单次最大写入值highWaterMark
let flag = ws.write("1");
console.log({ flag });//true
flag = ws.write("1");
console.log({ flag });//false
flag = ws.write("1");
console.log({ flag });//false
flag = ws.write("14444444");
console.log({ flag });//false
ws.end(); //write+close,没有调用 end 是不会调用 触发close的,看到这里的小伙伴可以尝试注释end() 看看close的console是否有打印
  • 效果

Nodejs中可写流write的实现方法

自定义可写流initWriteStream

继承EventEmitter发布订阅
const EventEmitter = require("events");
const fs = require("fs");
class WriteStream extends EventEmitter {}
module.exports = WriteStream;
链表生成队列做文件读取的缓存

链表&队列的实现

https://juejin.cn/post/6973847774752145445

// 用链表 生成队列 对 文件缓存区的读取 进行优化
const Queue = require("./queue");
初始化实例默认数据constructor()
 constructor(path, options = {}) {
    super();
    this.path = path;
    this.flags = options.flags || "w";
    this.encoding = options.encoding || "utf8";
    this.mode = options.mode || 0o666; //默认8进制 ,6 6 6  三组分别的权限是 可读可写
    this.autoClose = options.start || 0;
    this.highWaterMark = options.highWaterMark || 16 * 1024; //默认一次读取16个字节的数据
    this.len = 0; //用于维持有多少数据还没有被写入文件中
    //是否根据等待当前读取的最大文数据 排空后再写入
    this.needDrain = false; //
    // 缓存队列 用于存放 非第一次的文件读取 到的数据,因为第一次读取 直接塞入目标文件中
    // 除第一次 的文件读取数据的都存放再缓存中
    // this.cache = [];
    // 队列做缓存
    this.cache = new Queue();
    // 标记是否是第一次写入目标文件的标识
    this.writing = false;
    this.start = options.start || 0;
    this.offset = this.start; //偏移量
    this.open();
  }
  • this.mode 文件操作权限 默认0o666(0o表示8进制)

    • 3个6所占位置分别对应:文件所属用户对它的权限 ;文件所属用户组用户对它的权限;表示其他用户对它的权限

    • 权限由:r--可读(对应数值4),w--可写(对应数值2),x--可执行(对应数值1,例如文件夹下有 .exe 这样的标识 说明点击可以直接执行)组成

    • 所以默认情况下3组用户对文件的操作权限都是可读可写

open()
  • 调用fs.open()

  • 回调emit实例open方法,fs.open的返回值fd做参数传入

 open() {
    fs.open(this.path, this.flags, this.mode, (err, fd) => {
      this.fd = fd;
      this.emit("open", fd);
    });
  }
write()
  • 转化实例传入的需要写入的文件数据格式为buffer

  • 判断写入数据长度是否大于highWaterMark,如果达到预期后,文件读取到的数据存放再缓存里 不直接写入目标文件(这里要排除是否是第一次读取文件)

  • 执行实例write 传入的cb 并调用clearBuffer 清空缓存

  • 判断 是否是第一次读取,第一次读取 直接写入调用 _write(待实现)

  • 缓存队列尾部offer 当前读取到的数据等待写入目标文件

 write(chunk, encoding = this.encoding, cb = () => {}) {
    //  将数据全部转换成buffer
    chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);

    this.len += chunk.length;
    // console.log({chunk},this.len )
    let returnValue = this.len < this.highWaterMark;
    //当数据写入后,需要在手动的将this.len--
    this.needDrain = !returnValue; //如果达到预期 后 的文件读取 到数据存放再缓存里 不直接写入目标文件
    //清空缓存 对用户传入的回调 进行二次包装
    let userCb = cb;
    cb = () => {
      userCb();
      //清空buffer
      this.clearBuffer();//马上实现
    };

    //此时需要判断 是否是第一次读取,第一次读取 直接写入调用 _write
    if (!this.writing) {
      // 第一次||缓存队列已清空完毕
      this.writing = true;
      // console.log("first write");
      this._write(chunk, encoding, cb);//马上实现
    } else {
    //缓存队列尾部offer 当前读取到的数据等待写入目标文件
      this.cache.offer({
        chunk,
        encoding,
        cb,
      });
    }
    return returnValue;
  }
clearBuffer()依次清空缓存队列
  • 队列执行顺序,先进先出原则

  • this.cache.poll() 依次拿取头部数据执行this._write写入目标文件

  • 缓存队列poll出来的data如果不存在,则说明是第一次写入的行为||缓存队列已清空。this.writing = false; 下次的文件读取可以直接写入目标文件

  • 如果this.needDrain又达到预期,文件读取到数据存放再缓存里 不直接写入目标文件

clearBuffer() {
    //写入成功后 调用 clearBuffer--》写入缓存第一个,第一个完成后,再继续 第二个
    let data = this.cache.poll();
    // console.log('this.cache',this.cache)
    if (data) {
      //有值 写入文件
      this._write(data.chunk, data.encoding, data.cb);
    } else {
      this.writing = false;
      if (this.needDrain) {
        // 如果是缓存,触发drain
        this.emit("drain");
      }
    }
  }
_write()
  • fs.open()是异步的,成功读取后fd会是一个number类型

  • 根据fd的type 决定是否订阅一次open,并回调自己(直到fd类型为number)

  • fd类型为number:调用fs.write,写入当前的chunk,

 _write(chunk, encoding, cb) {
    if (typeof this.fd !== "number") {
      return this.once("open", () => this._write(chunk, encoding, cb));
    }
    fs.write(this.fd, chunk, 0, chunk.length, this.offset, (err, written) => {
      this.offset += written; //维护偏移量
      this.len -= written; //把缓存的个数减少
      cb(); //写入成功
      // console.log(this.cache);
    });
  }

测试自定义的Writable

const WriteStream = require("./initWriteStream");

let ws = new WriteStream(bPath, {
  highWaterMark: 3,
});

let i = 0;
function write() {
  //写入0-9个
  let flag = true;
  while (i < 10 && flag) {
    flag = ws.write(i++ + "");
     console.log(flag);
  }
}
ws.on("drain", function () {
  // 只有当我们写入的数据达到预期,并且数据被清空后才会触发drain ⌚️
  console.log("写完了");
  write();
});

write();
  • 10个数字,依次写入,3次达到最大预期值,然后依次清空了3次缓存结果符合预期

Nodejs中可写流write的实现方法

  • 目标文件中查看是否正确写入了我们预期的数值

Nodejs中可写流write的实现方法

到此,相信大家对“Nodejs中可写流write的实现方法”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Nodejs中可写流write的实现方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Node中的可读流和可写流实例代码分析

这篇“Node中的可读流和可写流实例代码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Node中的可读流和可写流实例代码
2023-07-05

nodejs mysql 实现分页的方法

这两天学习了nodejs mysql 实现分页,很重要,所以,今天添加一点小笔记。代码如下var express = require('express'); var router = express.Router(); var settin
2022-06-04

node.js 利用流实现读写同步,边读边写的方法

如下所示://10个数 10个字节,每次读4b,写1b let fs=require("fs"); function pipe(source,target) {//先创建可读流,再创建可写流//先读一次,rs.on(data)//将读到的类
2022-06-04

详解nodeJS中读写文件方法的区别

导言:nodejs中所有与文件相关的操作都在fs模块中,而读写操作又是我们会经常用到的操作,nodejs的fs模块针对读操作为我们提供了readFile,read, createReadStream三个方法,针对写操作为我们提供了write
2022-06-04

Nodejs+express中间件实现文件上传的方法

小编给大家分享一下Nodejs+express中间件实现文件上传的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!用nodejs做项目时需要用到文件上传的功能,
2023-06-14

nodejs中sleep功能实现暂停几秒的方法

我在网上了解了一下nodejs中sleep功能,搜索了很多关于nodejs中sleep功能介绍,下面我来记录一下,有需要了解的朋友可参考。希望此文章对各位有所帮助。一 背景在使用nodejs爬虫的时候,经常会遇到别人的网站对频率的反爬机制,
2022-06-04

nodejs批量下载图片的实现方法

今天想获取一大批猫的图片,然后就在360流浪器搜索框中输入猫,然后点击图片。就看到了一大波猫的图片:http://image.so.com/iq=%E7%8...,我在想啊,要是审查元素,一张张手动下载,多麻烦,所以打算写程序来实现。不写不
2022-06-04

php中runtime不可写的解决方法

这篇文章主要介绍了php中runtime不可写的解决方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。php的框架有哪些php的框架:1、Laravel,Laravel是一款
2023-06-15

用nodejs实现json和jsonp服务的方法

一、JSON和JSONP JSONP的全称是JSON with Padding,由于同源策略的限制,XmlHttpRequest只允许请求当前源(协议,域名,端口)的资源。如果要进行跨域请求,我们可以通过使用html的script标记来进行
2022-06-04

iOS中读写锁的简单实现方法实例

目录废话开篇思考一、对于锁的类型的理解思考二、读写锁的实现逻辑思考三、简单封装读写锁,满足读写逻辑总结废话开篇 iOS 下的多线程的技术的应用衍生出了锁的机制,试想,如果 iOS 下没有多线程的概念,所有的代码都会在同步环境下执行,那么,也
2022-06-04

Go实现各类限流的方法

前 言 在开发高并发系统时,我们可能会遇到接口访问频次过高,为了保证系统的高可用和稳定性,这时候就需要做流量限制,你可能是用的 Nginx 这种来控制请求,也可能是用了一些流行的类库实现。限流是高并发系统的一大杀器,在设计限流算法之前我们先
2022-06-07

Redis限流的实现方法有哪些

本篇内容主要讲解“Redis限流的实现方法有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis限流的实现方法有哪些”吧!一、简单的限流基本原理当系统处理能力有限,如何组织计划外的请求对
2023-06-22

Android实现读写JSON数据的方法

本文实例讲述了Android实现读写JSON数据的方法。分享给大家供大家参考。具体如下: 1. 解析JSON:package de.vogella.android.twitter.json; import java.io.BufferedR
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录