Node 【Buffer 与 Stream】

文章目录

  • 🌟前言
  • 🌟Buffer
    • 🌟 Buffer结构
    • 🌟 什么时候用Buffer
    • 🌟 Buffer的转换
    • 🌟 Buffer使用
      • 🌟 创建Buffer
      • 🌟 字符串转Buffer
      • 🌟 Buffer转字符串
      • 🌟 拼接Buffer
      • 🌟 Buffer不支持的编码类型
      • 🌟 判断是不是Buffer
      • 🌟 获取字节长度
      • 🌟 判断两个Buffer字节是否相同
  • 🌟Nodejs Stream(流)
    • 🌟 Node.js Stream
    • 🌟为什么应该使用流
    • 🌟Stream的作用
    • 🌟Node.js Stream
    • 🌟四种基本的流类型
      • 🌟1.readStream 读取流
        • 🌟参数
        • 🌟事件
        • 🌟方法
      • 🌟2.writeStream 写入流
        • 🌟 事件
        • 🌟方法
          • 🌟 write()
          • 🌟end()
      • 🌟3.管道流
        • 🌟options
  • 🌟写在最后

在这里插入图片描述

🌟前言

哈喽小伙伴们,新的专栏 Node 已开启;这个专栏里边会收录一些Node的基础知识和项目实战;今天我们开始这个专栏的第三篇文章,带领大家初识一下Buffer 与 Stream;让我们一起来看看吧🤘

🌟Buffer

JavaScript最初是被设计为处理html文档的,因此并不善于处理二进制数据。Node中需要处理网络协议、操作数据库、处理图片、文件上传等,还需要处理大量二进制数据,为此Node提供了Buffer类,该类封装了对访问连续内存块的操作,可以处理内存中的数据及创建、切分缓冲区,还可以在两个缓冲区之间复制内存数据。

🌟 Buffer结构

Buffer是一个典型的Javascript和C++结合的模块,性能相关部分用C++实现,非性能相关部分用javascript实现。

node在进程启动时Buffer就已经加装进入内存,并将其放入全局对象,因此无需require

Buffer对象:类似于数组,其元素是16进制的两位数。

🌟 什么时候用Buffer

纯粹的Javascript支持unicode码而对二进制不是很支持,当解决TCP流或者文件流的时候,处理流是有必要的,我们保存非utf-8字符串,2进制等等其他格式的时候,我们就必须得使用”Buffer“。

🌟 Buffer的转换

Buffer对象可以和字符串相互转换,支持的编码类型如下: ASCII、UTF-8、Base64、Binary(二进制)、Hex(十六进制)

🌟 Buffer使用

方法类型描述
Buffer.from(array)创建array 创建一个新的 Buffer
Buffer.from(string[,encoding])创建新建一个包含所给的 JavaScript 字符串 string 的 Buffer 。 encoding 参数指定 string 的字符编码。
Buffer.alloc(size[,val[,encoding]])创建分配一个大小为 size 字节的新建的 Buffer 。 如果 fill 为 undefined ,则该 Buffer 会用 0 填充。
Buffer.concat(list[,totallength])合并返回一个合并了 list 中所有 Buffer 实例的新建的 Buffer
buf.toString([encoding], [start], [end])返回根据 encoding 指定的字符编码解码 buf 成一个字符串。
buf.toJSON()返回返回 buf 的 JSON 格式。
Buffer.isEncoding(encoding)检测如果 encoding 是一个支持的字符编码则返回 true,否则返回 false 。
Buffer.isBuffer(obj)检测如果 obj 是一个 Buffer 则返回 true ,否则返回 false 。
Buffer.byteLength(buf)获取获取字节长度
buf.equals(otherBuffer)检测如果 buf 与 otherBuffer 具有完全相同的字节,则返回 true,否则返回 false。

🌟 创建Buffer

Buffer.from(array)
Buffer.from(string[,encoding])
Buffer.alloc(size[,val[,encoding]])

🌟 字符串转Buffer

# 默认UTF-8
Buffer.from(string[,encoding])

🌟 Buffer转字符串

buf.toString([encoding], [start], [end])

🌟 拼接Buffer

Buffer.concat(list[,totallength])

🌟 Buffer不支持的编码类型

Buffer.isEncoding(encoding)

🌟 判断是不是Buffer

Buffer.isBuffer(obj)

🌟 获取字节长度

Buffer.byteLength(buf)

🌟 判断两个Buffer字节是否相同

如果 buf 与 otherBuffer 具有完全相同的字节,则返回 true,否则返回 false。

buf.equals(otherBuffer)

🌟Nodejs Stream(流)

在之前我们学习过fs模块,fs模块中有fs.readFile 与 fs.writeFile 这两个方法读取和写入操作,但是这两个方法时将文件作为一个整体做读取、写入操作。

  • fs.readFile 将文件做为整体读入缓存区
  • fs.writeFile 将数据做为整体写入文件

假设我们要读取的文件为100G,内存只有8G,那么内存根本无法容纳这100G的数据,那么我们该如何去操作这些大数据呢?

假设客户端向服务器端传递100G的数据,数据是分为一小段一小段进行传输的。到了服务器端再将其组合起来。

传输数据的时候最小单位就是字节。

🌟 Node.js Stream

Stream是Node.js中处理数据的抽象接口,Node中有很多对象实现了这个接口。

Stream是Node.js中非常重要的一个模块,应用广泛。一个流是一个具备了可读、可写或既可读又可写能力的接口,通过这些接口,我们可以和磁盘文件、套接字、HTTP请求来交互,实现数据从一个地方流动到另一个地方的功能。

例如:对http服务器发起请求的request对象就是一个Stream,还有stdout(标准输出)

🌟为什么应该使用流

在node中,I/O都是异步的,所以在和硬盘以及网络的交互过程中会涉及到传递回调函数的过程。你之前可能会写出这样的代码:

var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    fs.readFile(__dirname + '/data.txt', function (err, data) {
        res.end(data);
    });
});
server.listen(8000);

上面的这段代码并没有什么问题,但是在每次请求时,我们都会把整个data.txt文件读入到内存中,然后再把结果返回给客户端。想想看,如果data.txt文件非常大,在响应大量用户的并发请求时,程序可能会消耗大量的内存,这样很可能会造成用户连接缓慢的问题。

其次,上面的代码可能会造成很不好的用户体验,因为用户在接收到任何的内容之前首先需要等待程序将文件内容完全读入到内存中。

所幸的是,(req,res)参数都是流对象,这意味着我们可以使用一种更好的方法来实现上面的需求:

var http = require('http');
var fs = require('fs');

var server = http.createServer(function (req, res) {
    var stream = fs.createReadStream(__dirname + '/data.txt');
    stream.pipe(res);
});
server.listen(8000);

在这里,.pipe()方法会自动帮助我们监听data和end事件。上面的这段代码不仅简洁,而且data.txt文件中每一小段数据都将源源不断的发送到客户端。

除此之外,使用.pipe()方法还有别的好处,比如说它可以自动控制后端压力,以便在客户端连接缓慢的时候node可以将尽可能少的缓存放到内存中。

🌟Stream的作用

传统程序在执行过程中,会边读边写,读写的速度不一样会导致数据丢失;且内存受限,读取存取速度有限。采用流以后程序会读一部分写一部分,保障数据不缺失。

Stream的作用如下:

  • 保证程序运行效率
  • 防止数据丢失
  • 防止内存的溢出

🌟Node.js Stream

Stream是Node.js中处理数据的抽象接口,Node中有很多对象实现了这个接口。 例如:对http服务器发起请求的request对象就是一个Stream,还有stdout(标准输出)

该stream模块可以使用访问:

const stream = require('stream');

🌟四种基本的流类型

  • Readable - 读取流 (例如 fs.createReadStream())
  • Writable - 写入流 (例如写 fs.createWriteStream())
  • Duplex - 读写流(即双工流) (例如 net.Socket)
  • Transform - 读写流(操作被写入数据,然后读出结果) (例如 zlib.createDeflate())

🌟1.readStream 读取流

fs.createReadStream(path,[opts]);  //创建可读流

🌟参数

  • path 创建读取流指定的文件路径
  • opts
    • flags 对文件采取何种操作,默认为 ‘r’
    • encoding 指定 编码 ,默认为null
    • start 用整数表示文件 开始 读取的字节数的索引位置
    • end 用整数表示文件 结束 读取的字节数的索引位置(包括end位置)
    • highWaterMark 最高水位线,停止从底层资源读取前内部缓冲区最多能存放的字节数。缺省为 64kb
{"encoding":"utf-8","start":0,"end":2,"highWaterMark":4}

🌟事件

  • data 当数据读取的时候
  • end 没有更多的数据可读时触发
  • error 当发生错误时候触发

🌟方法

  • setEncoding 指定 编码
  • pause() 读取数据暂停(什么时候暂停?读入流大于写入流调用)
  • resume() 通知对象 恢复 触发data事件继续读取数据
  • pipe() 管道 由读取流安全的传输到下一个流

🌟2.writeStream 写入流

fs.createWriteStream(path,[opts]);  //创建一个可写入流
  • path 读取的文件路径
  • options
    • flags 对文件采取何种 操作 ,默认为 ‘w’
    • encoding 指定 编码 ,默认为null
    • autoClose 是否 关闭 文件描述符
    • start 用整数表示文件 开始 字节数的写入位置
    • highWaterMark 最高水位线,write()开始返回 false 的 缓冲大小 。缺省为 16kb

🌟 事件

  • drain 当前内存数据完全都写入流的时候触发
  • finish 当数据全部都写完后触发

🌟方法

🌟 write()
write(chunk,[encoding],[callback])

要往写入流写入数据的时候触发

参数

  • chunk 要 写入 的数据,Buffer或字符串对象,必须指定
  • encoding 写入 编码 ,chunk为字符串时有用,可选
  • callback 写入成功后的 回调

返回值为布尔值,系统缓存区定满时为false,未满时为true

🌟end()
writable.end(chunk,[encoding],[callback]);

在写入文件时,当不再需要写入数据时可调用该方法关闭文件。 迫使系 统缓存区的数据立即写入文件中。

🌟3.管道流

管道流,pipe()方法的初衷,是将数据的滞留量限制到一个可接受的水平,以使得不同速度的来源和目标不会淹没可用内存。

readStream.pipe(writeStream,[options]);

🌟options

  • end 为true时表示数据读取完毕后立刻将缓存区中的数据写入目 标文件并 关闭 文件 无论哪一种流,都会使用.pipe()方法来实现输出和输出。
fs.createReadStream().pipe(fs.createWriteStream());
  • pipe()函数很简单,它仅仅是接受一个源头src并将数据输出到一个可写的流dst中:
src.pipe(dst)
  • pipe(dst)将会返回dst因此你可以链式调用多个流:
a.pipe(b).pipe(c).pipe(d)

上面的代码也可以等价为:

a.pipe(b);
b.pipe(c);
c.pipe(d);

🌟写在最后

更多Node知识以及API请大家持续关注,尽请期待。各位小伙伴让我们 let’s be prepared at all times!

✨原创不易,还希望各位大佬支持一下!
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/12837.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java每日一练(20230417)

目录 1. N 皇后 🌟🌟🌟 2. 搜索二维矩阵 🌟🌟 3. 发奖金问题 🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 …

权限控制_SpringSecurity

认证-授权 认证:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁。 授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作…

Node 内置模块 【fs模块】

文章目录 🌟前言🌟fs模块🌟 使用fs模块🌟 异步编程和同步编程🌟 异步编程🌟 同步编程 🌟常用操作🌟 文件操作🌟 readFile异步读取文件🌟 readFileSync同步读取…

YOLOv8 更换主干网络之 GhostNetV2

《GhostNetV2:Enhance Cheap Operation with Long-Range Attention》 轻量级卷积神经网络(CNN)是专门为在移动设备上具有更快推理速度的应用而设计的。卷积操作只能捕捉窗口区域内的局部信息,这防止了性能的进一步提高。将自注意力引入卷积可以很好地捕捉全局信息,但这将大…

【系统集成项目管理工程师】项目进度管理

💥十大知识领域:项目进度管理 主要考计算题 项目进度管理包括以下 7 个过程: 规划进度管理过程定义活动过程排列活动顺序过程估算活动资源过程估算活动持续时间过程制定进度计划过程控制进度过程 一、规划进度管理过程 制定政策、程序和文档以管理项目进…

JeecgBoot 3.5.1 版本发布,开源的企业级低代码平台

项目介绍 JeecgBoot是一款企业级的低代码平台!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue3,Mybatis-plus,Shiro,JWT 支持微服务。强大的代码生成器让前后端代码一键生成! JeecgBoot引领…

苹果电容笔值得买吗?ipad电容笔推荐平价

在当今时代,高科技已经成为推动数字产品发展的重要推动力。无论是在工作上,还是在学习上,大屏幕都能起到很好的作用。IPAD将会更好地融入我们的生活,不管是现在还是未来。而ipad配上一支简单的电容笔,不仅可以提高工作…

几分种学会React Router v6使用

React路由可以实现页面间的切换。 传送门:英文文档 中文教程: https://www.reactrouter.cn/docs/getting-started/tutorial 1.基础使用 1.安装react-router npm i react-router-dom62.配置根组件app.js import { React, lazy, Suspense } from "…

C++ -3- 类和对象 (中) | 构造函数与析构函数(一)

文章目录 1.类的6个默认成员函数2.构造函数3.析构函数构造函数与析构函数应用场景缺省值初始化 1.类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自…

【文章学习系列之模型】FEDformer

本章内容 文章概况模型流程主要结构Frequency Enhanced Decomposition Architecture(频率增强分解结构)Fourier enhanced blocks and Wavelet enhanced blocks(傅里叶增强模块和小波增强模块)Fourier Enhanced Structure&#xff…

【Java 数据结构】优先级队列 (堆)

🎉🎉🎉点进来你就是我的人了 博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔🦾&am…

快速精简软件,如何让软件缩小到原来的5%大小,从删除文件入手,到修改C++引用库,合规解决存储问题

Hi~大家好,今天制作一个简单的精简软件的教学~ 事先说明下,精简软件并不违反任何规定,尤其是开源软件,这里也仅讨论开源软件的修改,根据几乎所有开源软件的开源规则,精简软件,本质也就是修改软件…

戴尔G3 Ubuntu18.04双系统安装

ROS学习需要使用Linux系统,首先就是Ubuntu,我选择的是18.04.6这个版本,因为后面我要使用以Jetson Nano为主控的Jetbot进行ROS编程,Jetbot所带的出厂镜像就是18.04,为了方便程序移植,以及减少不必要的麻烦。…

【消息队列】聊一下Kafka副本机制

副本机制的好处 副本在分布式系统下,不同的网络互联的机器保存同一份数据。我们知道在分布式系统中,都会通过数据镜像、数据冗余的方式来提升高可用性。 提供数据冗余:这点比较好理解,说白了就是通过数据冗余在不同的服务器上&a…

大家副业都在做什么?csgo搬砖靠谱的副业推荐给你

从来没想过,以前只会玩CSGO的男孩子,现在居然能借助游戏赚到钱了!甚至不需要什么专业的技巧,简简单单 在steam平台选择有利润的道具后,再上架到国内网易BUFF平台,赚取“信息差”差价而已! 谁大…

SpringCloud学习(六)——Feign的简单使用

文章目录 1. Feign 的使用1.1 引入依赖1.2 添加注解1.3 编写Feign客户端1.4 测试 2. Feign中的自定义配置2.1.配置文件方式2.2.Java代码方式 3. Feign 性能优化4. Feign的抽取式使用4.1 抽取配置4.2 引入依赖4.3 指明Client 在此之前,我们服务之间需要进行调用的时候…

读懂MAC地址

MAC地址是一种用于标识计算机网络设备的唯一地址。它是由48个二进制数字组成的,通常表示为12个十六进制数字,每两个数字之间用冒号或连字符分隔开。MAC地址由设备制造商在生产过程中分配,以确保网络上每个设备都有唯一的标识符。 MAC地址的规…

第11章_常用类和基础API

第11章_常用类和基础API 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 1. 字符串相关类之不可变字符序列:String 1.1 String的特性 java.lang.String 类代表字符串…

【大数据之Hadoop】十七、MapReduce之数据清洗ETL

ETL是将业务系统的数据经过抽取、清洗转换之后加载到数据仓库的过程,目的是将分散、零乱、标准不统一的数据整合到一起,为决策提供分析依据。 ETL的设计分三部分:数据抽取、数据的清洗转换、数据的加载。 1 ETL体系结构 ETL主要是用来实现…

LLM总结(持续更新中)

引言 当前LLM模型火出天际,但是做事还是需要脚踏实地。此文只是日常学习LLM,顺手整理所得。本篇博文更多侧重对话、问答类LLM上,其他方向(代码生成)这里暂不涉及,可以去看综述来了解。 之前LLM模型梳理 …