美文网首页
第八节: 内置模块(四): Buffer 缓存区与fs文件模块

第八节: 内置模块(四): Buffer 缓存区与fs文件模块

作者: 时光如剑 | 来源:发表于2020-12-20 23:07 被阅读0次

    1.Buffer缓存区

    缓存区: 缓存区就是内存中开辟一块临时区域用于存储需要运算的字节码

    从结构上看Buffer非常像一个数组,他的元素为16进制的两位数

    1.1. Buffer的基本概念

    JavaScript语言自身只有字符串数据类型,没有二进制数据类型,二进制可以存储电脑中任何的数据(比如:一段文字,一张图片,一个视频,在电脑中都是采用二进制的的方式进行存储的)
    NodeJS是服务器端在处理像TCP(网络)流或文件流(也叫字节流),必须使用到 二进制数据.因此在NodeJs中增加了一个Buffer类,该类用来创建一个专门存放二进制数据的缓存区

    <Buffer e4 bd a0 e9 a5 bf e5 90 97 3f e6 88 91 e5 a5 bd e9 a5 bf e5 95 8a 21>
    

    Buffer是一个和二进制很像的十六进制的字节码.两个段码表示一个字节
    一个二进制表示一个位
    一个字节是8个二进制位
    一个16进制是2的4次方

    // 比如e4
    // 16进制表示式e4
    // 2进制表示 11100100
    // 11100100  正好是一个字节
    在内存中这个字节码可以直接使用,如果存到硬盘里,会自动转为二进制存储.,这样转二进制会很方便
    
    2.2. Buffer 创建

    Buffer是一个全局的类,不需要加载可以直接使用

    2.2.1 创建指定长度的缓存区

    在node.js中默认使用utf-8编码,一个中文一般占3个字节

    // 创建10个字节的缓存区
    var buf = new Buffer(10)
    
    // Buffer()的写法已经弃用, 需要改用Buffer.alloc() 
    
    // 写入一个字符a
    buf.write('a')
    console.log(buf)
    

    这个方法已经被废弃,不要在使用了.

    2.2.2 指定数组长度创建Buffer
    var buf = Buffer.alloc(10)
    console.log(buf)
    

    没什么意义,你知道你要存的内容是多大吗?

    2.2.3 使用 from 创建Buffer
    var str = 'Hello wrold'
    
    // 将一个字符串保存到buffer中
    var buf = Buffer.from(str)
    
    console.log(buf)
    
    // 注意from 的方法参数不能是数字
    // 类型可以为string, Buffer, ArrayBuffer, Array, or Array-like Object
    
    2.3. 写入缓存区
    buf.write("写入缓存区")
    
    2.4. 缓存区复制
    let str = 'Hello wrold'
    let buf = Buffer.from(str)
    let bff = Buffer.alloc(12)
    buf.copy(bff)
    
    2.5. 实例常用方法
    2.5.1 buf.length

    获取buf的长度

    buf.length;
    
    2.5.2 buf.toString()

    将buf的内容转为字符串

    语法

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

    参数

    1. encoding 可选 , 指定编码格式 默认utf8
    2. start 可选, 开始位置 默认最开始
    3. end 可选 结束位置 默认结束位置

    返回值

    ​ 解码缓冲区数据并使用指定的编码返回字符串

    let buf = Buffer.from('我是谁')
    // 不传参
    console.log(buf.toString())
    
    // 指定编码, 以及转换的数据
    console.log(buf.toString('utf8', 3,6))
    
    2.5.3 buf.fill()

    语法

    ​ buf.fill(value [, start, [, end]])

    参数

    1. value 必须: 初始化数据
    2. start 初始化开始的位置
    3. end 初始化结束的位置
    2.5.4 buf.slice()

    用法与字符串的slice用法一样

    let buf = Buffer.from('我是谁')
     
    console.log(buf.slice(-6,-3))
    
    2.5.5 buf.copy()

    从目标buf中拷贝内容

    语法

    ​ buffer.copy(目标buf, 写法buf开始的位置, 拷贝buffer开始位置, 拷贝buffer结束位置)

    let buf = Buffer.from('我是谁')
    let buf2 = Buffer.from([0,0,0,0,0])
    // 将buf里从下标3开始,到下标6的自己拷贝到 buf2 从buf2第一个字节开始写入
    buf.copy(buf2,1, 3,6)
    
    2.6.类常用的方法(静态方法)
    2.6.1 Buffer.isBuffer()

    判断一个对象是不是Buffer对象

    语法

    ​ Buffer.isBuffer(obj)

    参数

    ​ obj 需要判断的对象

    返回值

    ​ 布尔值

    let buf = Buffer.from('我是谁')
    
    console.log(Buffer.isBuffer(buf))   // true
    
    2.6.2 Buffer.concat()

    语法 Buffer.concat(), 接受一个数组参数, 数组可以说是buffer数组

    ​ Buffer.concat([buf, buf2])

    返回值:

    ​ 返回合并后的buffer

    let buf = Buffer.from('我')
    let buf2 = Buffer.from('是谁')
    console.log(buf)
    console.log(buf2)
    let buf3 = Buffer.concat([buf,buf2])
    console.log(buf3.toString())
    

    注意点

    1. Buffer 是用于处理二进制数据流
    2. Buffer一个元素就是一个字节;
    3. 实例类似整数数组, 但和数组不一样的是,一旦实例,那么大小将固定
    4. 内存不 是由V8分配的, 是C++代码在V8堆外分配的物理内存

    2.fs文件模块(掌握)

    由于node.js是服务器端的程序,必须要有读写文件操作,在原生JS中没有这样的功能.
    在Node中如果要读写文件,必须使用文件系统模块(fs),提供了文件操作的所有功能

    js在浏览器端是不能进行I/O操作的,是为了保护客户端的安全, node内置的js模块, 让js能够在在node环境执行的时候, 可以操作服务器上的资源文件,也就是给与js I/O 操作的能力

    2.1. 读取文件

    文件的读写有两种方式:

    第一种方式是将硬盘是上的内容全部读入内容以后才触发回调函数
    第二种方式 是流式读取:将数据从硬盘中读取一节就触发一次回调函数,也就是读取一节数据处理一节数据
    实现大文件操作

    在直接读取中又分为两种,同步读取和异步读取

    2.1.1 异步方式读取
    fs.rendFile(文件路径, 回调函数)
    

    定义一个回调函数,接受读取到的内容

     // 直接读取文件 -- 异步
    var fs = require('fs');
    fs.readFile("./file1.txt", function (err, data) {
        console.log(data)
        // err 错误对象,如果有错则有值,没有报错则为null
        // data 是Buffer数据流,如果需要显示数据通过data.toString
    })
    
    // 可以使用特殊的方式,就是第二个参数传入数据格式,那么data将直接显示数据
    var fs = require('fs');
    fs.readFile("./file1.txt", "utf-8",function (err, data) {
        console.log(data)
    })
    



    实例:将服务器上读取的文件内容通过服务器返回给浏览器

    // 创建服务器用的模块
    const http = require('http');
    // 这是读取文件用模块
    const fs = require('fs')
    
    // 创建一个服务器
    const server = http.createServer(function (req, res) {
      // 设置响应头
      res.writeHead(200, { 'Content-Type': 'text/html;charset=UTF-8' });
      // 读取文本文件,
      fs.readFile('./test.txt', function (err, data) {
        // 如果数据读取成功,将数据返回
        res.end(data);
      })
    })
    
    // 监听端口
    server.listen(3000);
    console.log('服务器已经在3000端口启动了')
    

    2.1.2 同步读取文件

    同步采用赋值的方式返回数据
    几乎所有的fs函数都有同步版本,只需要在异步版本的函数后面添加Sync即可

    fs.readFileSync(文件路径)
    

    示例:

    // 直接读取文件 -- 同步
    var fs = require('fs');
    var data = fs.readFileSync("./file1.txt")
    console.log(data.toString());
    
    

    我们发现同步版本并没有报错接受,如果同步有错,系统将会自动报错

    ,所以异步方法,如果有错系统不会报错,会将报错传给回调自行处理

    2.2. 写入文件
    2.2.1 异步版本

    语法方式:

    fs.writeFile('文件名','数据',function(err){ /* 数据写入失败时的回调函数*/ })
    

    示例:

    // 写文件 -- 异步
    var fs = require('fs');
    var data = "<h2>我是通过fs模块写入的文件</h2>"
    fs.writeFile("wuwei.html", data, function (err) {
      console.log(err)
    })
    
    // 可以传入写入写入的字符编码
    fs.writeFile("wuwei.html", data, 'utf8' ,function (err) {
      console.log(err)
    })
    
    // 如果写入的是buffer ,那么就可以忽略编码
    const content = Buffer.from("this is a test")
    fs.writeFile("wuwei.html", content, function (err) {
      console.log(err)
    })
    
    2.2.2 同步版本
    fs.writeFileSync(文件路径, 数据)
    

    示例:

    var data = "<h2>我是通过fs模块写入的文件</h2>"
    fs.writeFileSync("wuwei.html", data)
    
    2.3. 追加写入内容
    2.3.1 异步追加
    fs.appendFile(文件路径, 数据, 回调函数)
    

    示例:

    var data = "<h2>我是通过fs模块写入的文件</h2>"
    fs.appendFile("./wuwei.html",data,(err) => {
        console.log(err)
    })
    
    2.3.2 同步追加
    fs.appendFileSync(文件路径, 数据)
    

    示例:

    var data = "<h2>我是通过fs模块写入的文件</h2>"
    fs.appendFileSync("./wuwei.txt",data)
    
    2.4. 读取文件/文件夹信息
    2.4.1 语法方式

    异步读取

    fs.stat("文件名",function(err,stats){ 
        //state是文件的信息对象,包含了常用个文件信息
    })
    

    同步读取

    const stat = fs.statSync("./node")
    
    2.4.2 示例
    var fs = require("fs");
    fs.stat("index.json", function (err, stats) {
      console.log(stats)
    })
    

    打印stats对象

    Stats {
      dev: 226428394,
      mode: 33206,
      nlink: 1,
      uid: 0,
      gid: 0,
      rdev: 0,
      blksize: undefined,
      ino: 10414574138374020,
      size: 17,                                     //文件大小,字节数
      blocks: undefined,
      atimeMs: 1566988486138.9304,                 //
      mtimeMs: 1566625311439.442,
      ctimeMs: 1566625311439.442,
      birthtimeMs: 1566625188201.4536,
      atime: 2019-08-28T10:34:46.139Z,              // 上一次文件访问时间
      mtime: 2019-08-24T05:41:51.439Z,              // 文件内容修改时间
      ctime: 2019-08-24T05:41:51.439Z,              // 文件状态改变时间 
      birthtime: 2019-08-24T05:39:48.201Z           // 第一次创建时间
    }
    
    2.4.3 文件信息对象的方法

    语法

    stats.isFile() 判断是不是文件
    stats.isDirectory() 判断是不是文件夹(目录)

    判断是不是文件

    var fs = require("fs");
    fs.stat("index.json", function (err, state) {
      console.log(state.isFile())
    })
    
    2.4.4 修改文件名 rename
    var fs = require("fs");
    fs.rename("./text", 'test.txt', err => {
        if(err) throw err
        console.log("done!")
    })
    
    2.5. 删除文件

    语法:

    fs.unlink(path,callback)   
    // 断开连接式的删除文件
    

    示例:

    fs.unlink("wuwei.html", function (err) {
      if (err) {
        throw err
      } else {
        console.log("删除成功")
      }
    })
    
    2.6. 新增目录

    语法:

    fs.mkdir(path,callback)
    

    示例:

    fs.mkdir("./wuwei",function(err){
        // 创建失败的回调
    })
    
    2.7. 读取目录中的文件列表
    fs.readdir(path,callback)
    

    示例:

    fs.readdir("./wuwei",function(err,list){
        console.log(err);
        console.log(list)
        // list 是读取文件夹列表
    })
    // 如果文件夹存在的话,list是 一个node文件夹下所有文件以及文件夹的数组集合
    // 如果文件夹不存在就是err
    
    2.8. 删除空文件夹
    fs.rmdir(path,callback)
    

    示例:

    fs.rmdir("./wuwei",function(err){
        // err  报错信息
    })
    

    只能删除空文件夹,不能删除空文件夹

    2.9 监听文件是否改变
    // watch是监听 文件夹内所有的文件变化
    fs.watch("./",{
        recursive: false // 默认是flase 是否递归监听
    }, (changeType, filename) => {
        console.log(chaneType)  // 改变的类型 ,是修改一个文件 还是新增文件亦或是删除文件
        console.log(filename)  // 修改的文件名字
    })
    
    
    // watchFile 是监听一个文件的变化
    fs.watchFile('./node/1.txt',(c,p) => {
        console.log(p);
        console.log(c)
    })
    

    p监听文件改变之前stats

    c监听文件改变之后(即当前文件)stats

    3.fs流读写方式(掌握)

    用read读取文件 方法,会将文件整体读入缓存区,然后使用,用write方法写入文件的时候,会将文件整体读入缓存区,在修改后整体写入文件,
    也就是说在node中无论read还是write都是把文件视为一个整体.Node需要在内存中开辟与文件相同大小的缓存空间,如果文件小,的确没有什么问题,如果是一个非常大的文件,超过内存大小怎么办?

    3.1. Stream 流介绍

    应用程序中,流是一种有序的,有起点和终点的字节数据的传输方式.在应用程序中各种对象之间交流与传输数据的的时候,总是先将该对象中所包含的数据转换为各种形式的流数据(即字节数据),在通过流的传输,到达目的对象后在将流数据转换为该对象中可以使用的数据

    所有互联网传输数据都是以流的方式传输的,也就是说都是一节一节的

    3.2. 流的操作
    3.2.1 流式读取

    语法

    // 1. 创建读取流
    var stream = fs.createReadStream(path)
    
    
    // 2. 绑定data事件接受数据
    stream.on("data",function(data){
        console.log(data)
        console.log(1) // 打印几次,表示数据分了几次流
    })
    
    
    // 3. 绑定end事件表示读取完毕
    stream.on("end",function(){
        console.log("数据流读取完毕")
    })
    
    
    // 4. 绑定error错误事件
    stream.on("error",function(err){    
        throw err   
    })
    
    

    示例:

    var fs = require("fs");
    // 创建一个可读流
    var stream = fs.createReadStream("./file2.txt");
    // 监听data事件,每读一段流数据就执行一次回调函数
    stream.on("data", function (data) {
      console.log(data)
    })
    



    每一节数据流的长度是65536字节,大小是65536/1024=64kb,也就是每一节的大小是64kb,可以通过data.length查看

    读取流事件:end 表示在读取流读取完毕后触发的事件

    stream.on("end", function () {
      console.log("读取完毕")
    })
    

    读取流事件:error 表示在读取流读取错误时后触发的时间

    stream.on("end", function () {
      console.log("读取完毕")
    })
    
    3.2.2 以流的方式写文件

    语法

    // 1. 创建写入流
    
    var stream = fs.createWriteStream(path)
    
    // 2. 写入数据
    
    stream.write("数据1")
    
    
    // 3. 写入完毕后结束写入流
    
    stream.end()
    
    
    // 4. 数据写入完成事件
    
    stream.on("finish",function(){
    
    })
    
    // 5. 绑定error出错事件
    
    stream.on("error",function(err){
    
    })
    

    示例:

    var fs = require("fs");
    
    //  创建一个写入流
    var stream = fs.createWriteStream("./file3.txt");
    
    // 写入数据
    stream.write("面包吃完了");
    stream.write("牛奶喝光了");
    stream.write("钱也花完了");
    stream.write("工作也丢了");
    stream.write("最悲催的是我迷路了");
    stream.end();     // 已流的方式写入数据必须显示的声明结束
    

    写入流可以通过监听finish事件,来处理在写入流完成后要做的事情

    stream.on("finish", function () {
      console.log("写入完成")
    })
    

    写入流错误事件,error,在写入错误时触发回调

    stream.on("error", function (err) {
      console.log(err)
    })
    
    3.3. fs管道方式(掌握)
    3.3.1. 什么 是管道

    管道是Node.Js中流的实现机制.
    管道(pipe)提供了一个输出流到输入流传入数据的一个机制.通常我们用于一个流中获取数据并将数据传递到另外一个流中.

    3.3.2. 管道语法
    1. 语法

      输出流.pipe(输入流)

    2. 作用

      管道可以实现对大文件的操作(文件 大小超过内存)

    实例: 不采用管道方式复制文件
    var fs = require("fs");
    // 创建读取流和写入流
    var s1 = fs.createReadStream("./file2.txt");
    var s2 = fs.createWriteStream("./file3.txt");
    
    // 读一节数据写入一节数据
    s1.on("data", function (d) {
      s2.write(d)
    })
    
    // 读入完成后,写入完成
    s1.on("end", function () {
      s2.end();
      console.log("复制完成")
    })
    
    使用管道复制文件
    var fs = require("fs");
    // 创建读取流和写入流
    var s1 = fs.createReadStream("./file2.txt");
    var s2 = fs.createWriteStream("./file3.txt");
    
    s1.pipe(s2);
    
    3.4. 链式流

    将多个管道连接起来,实现链式操作

    输入流.pipe(中转流).pipe(中转流).pipe(...).pipe(输出流)

    例子:使用链式流压缩文件

    var fs = require("fs");
    //  引入压缩模块
    var zlib = require('zlib');
    
    // 创建引入引出流
    var s1 = fs.createReadStream("./file3.txt");
    var s2 = fs.createWriteStream("./file3.txt.zip");
    
    // 链式操作
    s1.pipe(zlib.createGzip()).pipe(s2)
    

    理解就好 ,后面基本上都是用框架

    相关文章

      网友评论

          本文标题:第八节: 内置模块(四): Buffer 缓存区与fs文件模块

          本文链接:https://www.haomeiwen.com/subject/fwumgktx.html