美文网首页
第八节: 内置模块(四): 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)

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

相关文章

  • node文件操作

    缓存区、文件系统、路径 1. 课程介绍 Ø Buffer缓存区(了解) Ø fs文件模块(了解) Ø fs读取文件...

  • 缓存区、文件系统、路径

    1. 课程介绍 ◆ Buffer缓存区(了解)◆ fs文件模块(了解)◆ fs读取文件(掌握)◆ ...

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

    1.Buffer缓存区 缓存区: 缓存区就是内存中开辟一块临时区域用于存储需要运算的字节码 从结构上看Buffer...

  • Node.js基本模块

    fs模块 node.js内置的fs模块就是文件系统模块,负责读写文件。与所有其他JavaScript模块不同的是,...

  • Node.js入门(五) : Nodejs模块API介绍

    本文主要介绍一下几个模块的API:文件操作fs path、Buffer缓冲区、Stream文件流、promise与...

  • 3-廖雪峰-node-fs模块

    fs文件读取模块 Node.js内置的fs模块就是文件系统模块,负责读写文件。 和所有其它JavaScript模块...

  • nodejs学习笔记

    参考 模块化 内置模块文件管理(fs)fs.readdirSync() //同步读取文件夹fs.readir() ...

  • Day11 文件系统

    fs模块 Node.js内置的fs模块就是文件系统模块,负责读写文件。和所有其它JavaScript模块不同的是,...

  • 6-2 Node.js 文件模块

    Node.js内置的fs模块就是文件系统模块,负责读写文件。 和所有其它JavaScript模块不同的是,fs模块...

  • Node.js之fs用法详解

    Node.js 内置的fs模块就是文件系统模块,负责读写文件。和所有其他JS模块不同的是,fs模块同时提供了异步和...

网友评论

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

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