<node.js中的buffer.Buffer.isBuffer方法使用说明_node.js
您的当前位置:首页正文

node.js中的buffer.Buffer.isBuffer方法使用说明_node.js

2023-12-05 来源:六三科技网

方法说明:

检测目标是否为buffer对象。将返回true 或 false。

语法:

代码如下:Buffer.isBuffer(obj)

接收参数:

obj 被检测的对象。

例子:

代码如下:var b = new Buffer(50); var c = b.toString('base64',0,10); var d = Buffer.isEncoding('base64'); var e = Buffer.isBuffer(b); console.log(d); //返回false console.log(e); //返回true

源码:

代码如下:// Static methodsBuffer.isBuffer = function isBuffer(b) { return util.isBuffer(b);};

小编还为您整理了以下内容,可能对您也有帮助:

node.js 读写文件的时候可以设置为binary吗

可以设置。
  读取文件的函数,Node.js 读取文件后,data是以二进制Buffer格式保存的,Blob格式的数据也是以二进制方式保存的,所以可以说data就是题主想要的 Blob binary data,不知道有没有解决题主的问题。
  var fs = require('fs')
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err
console.log('isBuffer: ' + Buffer.isBuffer(data)) // isBuffer: true
console.log(data) // <Buffer 72 6f ... >
})

node.js 读写文件的时候可以设置为binary吗

可以设置。
  读取文件的函数,Node.js 读取文件后,data是以二进制Buffer格式保存的,Blob格式的数据也是以二进制方式保存的,所以可以说data就是题主想要的 Blob binary data,不知道有没有解决题主的问题。
  var fs = require('fs')
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err
console.log('isBuffer: ' + Buffer.isBuffer(data)) // isBuffer: true
console.log(data) // <Buffer 72 6f ... >
})

Buffer简单理解及常用方法介绍

javascript 中对数据处理都是以字符串的形式,而对于二进制数据就不便于处理,所以 Buffer 便是用于读取或操作二进制数据的对象。

通俗来说Buffer其实就是处理数据的方法,这点在官网文档里解释的很详细。
Buffer 是内存拷贝,而不是内存共享。

Buffer 占用内存被解释为一个数组,而不是字节数组。比如,new Uint32Array(new Buffer([1,2,3,4])) 创建了4个 Uint32Array,它的成员为 [1,2,3,4] ,而不是[0x1020304] 或 [0x4030201]。
注意:Node.js v0.8 只是简单的引用了array.buffer里的 buffer ,而不是克隆(cloning)。

介绍一个高效的方法,ArrayBuffer#slice() 拷贝了一份切片,而 Buffer#slice() 新建了一份。

类: Buffer
Buffer 类是全局变量类型,用来直接处理2进制数据。 它能够使用多种方式构建

Buffer.from(array) 返回一个新的 Buffer,其中包含提供的八位字节数组的副本。
Buffer.from(arrayBuffer[, byteOffset [, length]]) 返回一个新的 Buffer,它与给定的 ArrayBuffer 共享相同的已分配内存。
Buffer.from(buffer) 返回一个新的 Buffer,其中包含给定 Buffer 的内容的副本。
Buffer.from(string[, encoding]) 返回一个新的 Buffer,其中包含提供的字符串的副本。
Buffer.alloc(size[, fill[, encoding]]) 返回一个指定大小的新建的的已初始化的 Buffer。 此方法比 Buffer.allocUnsafe(size) 慢,但能确保新创建的 Buffer 实例永远不会包含可能敏感的旧数据。
Buffer.allocUnsafe(size) 和 Buffer.allocUnsafeSlow(size) 分别返回一个指定大小的新建的未初始化的 Buffer。 由于 Buffer 是未初始化的,因此分配的内存片段可能包含敏感的旧数据。

1.ascii——ASCI,仅适用于ASCII字符集。
2.utf8——UTF-8,这种可变宽编码适用于Unicode字符集的任何字符,它已经成了Web世界的首选编码,也是Node的默认编码类型。
3.base64——Base64,这种编码基于64个可打印ASCII字符来表示二进制数据,Base64通常用于在字符文档内嵌入可以被转化成字符串的二进制数据,在需要时又可以完整无损的转换回原来的二进制格式。

Buffer简单理解及常用方法介绍

javascript 中对数据处理都是以字符串的形式,而对于二进制数据就不便于处理,所以 Buffer 便是用于读取或操作二进制数据的对象。

通俗来说Buffer其实就是处理数据的方法,这点在官网文档里解释的很详细。
Buffer 是内存拷贝,而不是内存共享。

Buffer 占用内存被解释为一个数组,而不是字节数组。比如,new Uint32Array(new Buffer([1,2,3,4])) 创建了4个 Uint32Array,它的成员为 [1,2,3,4] ,而不是[0x1020304] 或 [0x4030201]。
注意:Node.js v0.8 只是简单的引用了array.buffer里的 buffer ,而不是克隆(cloning)。

介绍一个高效的方法,ArrayBuffer#slice() 拷贝了一份切片,而 Buffer#slice() 新建了一份。

类: Buffer
Buffer 类是全局变量类型,用来直接处理2进制数据。 它能够使用多种方式构建

Buffer.from(array) 返回一个新的 Buffer,其中包含提供的八位字节数组的副本。
Buffer.from(arrayBuffer[, byteOffset [, length]]) 返回一个新的 Buffer,它与给定的 ArrayBuffer 共享相同的已分配内存。
Buffer.from(buffer) 返回一个新的 Buffer,其中包含给定 Buffer 的内容的副本。
Buffer.from(string[, encoding]) 返回一个新的 Buffer,其中包含提供的字符串的副本。
Buffer.alloc(size[, fill[, encoding]]) 返回一个指定大小的新建的的已初始化的 Buffer。 此方法比 Buffer.allocUnsafe(size) 慢,但能确保新创建的 Buffer 实例永远不会包含可能敏感的旧数据。
Buffer.allocUnsafe(size) 和 Buffer.allocUnsafeSlow(size) 分别返回一个指定大小的新建的未初始化的 Buffer。 由于 Buffer 是未初始化的,因此分配的内存片段可能包含敏感的旧数据。

1.ascii——ASCI,仅适用于ASCII字符集。
2.utf8——UTF-8,这种可变宽编码适用于Unicode字符集的任何字符,它已经成了Web世界的首选编码,也是Node的默认编码类型。
3.base64——Base64,这种编码基于64个可打印ASCII字符来表示二进制数据,Base64通常用于在字符文档内嵌入可以被转化成字符串的二进制数据,在需要时又可以完整无损的转换回原来的二进制格式。

Node.js的Buffer写入

Buffer写入的语法如下:

buf.write(string[,offset[,length]][,encoding])

即根据encoding的字符编码写入string到buf中的offset位置。length参数是写入的字节数。如果buf没有足够的空间保存整个字符串,就只会写入string的一部分。只部分解码的字符不会被写入。该方法返回实际写入的大小。参数含义如下:

    ●    String:写入的字符串。

    ●    Offset:开始写入的索引值,默认为0。

    ●    Length:写入的字节数,默认为buffer.length。

    ●    Encoding:使用的编码,默认为"utf8"。

Node.js的Buffer写入

Buffer写入的语法如下:

buf.write(string[,offset[,length]][,encoding])

即根据encoding的字符编码写入string到buf中的offset位置。length参数是写入的字节数。如果buf没有足够的空间保存整个字符串,就只会写入string的一部分。只部分解码的字符不会被写入。该方法返回实际写入的大小。参数含义如下:

    ●    String:写入的字符串。

    ●    Offset:开始写入的索引值,默认为0。

    ●    Length:写入的字节数,默认为buffer.length。

    ●    Encoding:使用的编码,默认为"utf8"。

node.js 基础操作

require 函数用来在一个模块中引入另外一个模块。传入一个模块名,返回一个模块导出对象。用法: let cc = require("模块名") ,其中模块名可以用绝对路径也可以用相对路径,模块的后缀名.js可以省略。例如:

require()函数用两个作用:

exports 对象用来导出当前模块的公共方法或属性,别的模块通过 require 函数使用当前模块时得到的就是当前模块的 exports 对象。用法: exports.name ,name为导出的对象名。例子:

mole.exports 用来导出一个默认对象,没有指定对象名,常见于修改模块的原始导出对象。比如原本模块导出的是一个对象,我们可以通过mole.exports修改为导出一个函数。如下:

3.加载第三方包

Node.js中使用 CommonJs 模块化机制,通过 npm 下载的第三方包,我们在项目中引入第三方包都是: let xx = require('第三方包名') ,究竟 require 方法加载第三方包的原理机制是什么,今天我们来探讨下。

require('第三方包名') 优先在加载该包的模块的同级目录 node_moles 中查找第三方包。

找到该第三方包中的 package.json 文件,并且找到里面的 main 属性对应的入口模块,该入口模块即为加载的第三方模块。

如果在要加载的第三方包中没有找到 package.json 文件或者是 package.json 文件中没有 main 属性,则默认加载第三方包中的 index.js 文件。

如果在加载第三方模块的文件的同级目录没有找到 node_moles 文件夹,或者以上所有情况都没有找到,则会向上一级父级目录下查找 node_moles 文件夹,查找规则如上一致。

如果一直找到该模块的磁盘根路径都没有找到,则会报错: can not find mole xxx 。

4.npm命令

npm 英文全称: node package manager ,npm 为你和你的团队打开了连接整个 JavaScript 天才世界的一扇大门。它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(package) (即,代码模块)。来自各大洲的开源软件开发者使用 npm 互相分享和借鉴。包的结构使您能够轻松跟踪依赖项和版本。我们平时开发项目都是需要使用npm下载依赖,常见的npm命令总结如下:

5.文件读取

var fs = require('fs')

同步:

var content = fs.readFileSync('hello.txt',{flag:'r',encoding:"utf-8"})

异步(默认):

flag:读取模式

encoding:编码格式

7.文件写入

var fs = require('fs')

格式:write=>w read=>r append =>a

异步:

8.文件删除

fs . unlink ( 'lc.txt' , function (){

9.buffer缓冲区

1、数组不能进行二进制数据的操作2、js数组不像java、python等语言效率高3、buffer内存空间开辟出固定大小的内存

let buf1 = Buffer.alloc(10)

console.log(buf1)

allocUnsafe(之前的一些内容)(效率高)

10.文件目录

var fs = require('fs')

fs.readdir(path,callback)

导入 readline 包

let readline = require('readline');

实例化接口对象(process对象,stdout/in输入输出)

question方法 提问

close 事件监听

11.文件流

var fs = require('fs')

语法: fs.createWriteStream(文件路径,【可选的配置操作】)

let ws = fs.createWriteStream("hello.txt",{flags:"w",encoding:"utf-8"});

let ws = fs.createWriteStream("hello.txt",{flags:"w",encoding:"utf-8"});

实践

fs.createReadStream(路径,【可选的配置项】)

文档

let rs = fs.createReadStream('hello.txt',{flags:'r',encoding:"utf-8"})

音乐

let rs = fs.createReadStream('snake.mp4',{flags:'r'})

读取时写入

let ws = fs.createWriteStream('a.txt',{flags:"w",encoding:"utf-8"})

createReadStream.pipe(createWriteStream)

链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。

接下来我们就是用管道和链式来压缩和解压文件。

创建 compress.js 文件, 代码如下:

代码执行结果如下:

执行完以上操作后,我们可以看到当前目录下生成了 input.txt 的压缩文件 input.txt.gz。

接下来,让我们来解压该文件,创建 decompress.js 文件,代码如下:

12.node事件

Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。

Node.js 几乎每一个 API 都是支持回调函数的。

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。

Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数.

没有使用 events 包 仅使用JavaScript事件监听进行事件驱动

Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。

当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。

这个模型非常高效可扩展性非常强,因为 webserver 一直接受请求而不等待任何读写操作。(这也称之为非阻塞式IO或者事件驱动IO)

在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。

Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:

以下程序绑定事件处理程序:

我们可以通过程序触发事件:

接下来让我们执行以上代码:

在 Node 应用程序中,执行异步操作的函数将回调函数作为最后一个参数, 回调函数接收错误对象作为第一个参数。

接下来让我们来重新看下前面的实例,创建一个 input.txt ,文件内容如下:

创建 main.js 文件,代码如下:

以上程序中 fs.readFile() 是异步函数用于读取文件。如果在读取文件过程中发生错误,错误 err 对象就会输出错误信息。

如果没发生错误,readFile 跳过 err 对象的输出,文件内容就通过回调函数输出。

执行以上代码,执行结果如下:

接下来我们删除 input.txt 文件,执行结果如下所示:

因为文件 input.txt 不存在,所以输出了错误信息。

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。

Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。所有这些产生事件的对象都是 events.EventEmitter 的实例。

events 模块只提供了一个对象:events.EventEmitter。EventEmitter 的核心就是事件触发与事件*功能的封装。

你可以通过require("events");来访问该模块。

EventEmitter 对象如果在实例化时发生错误,会触发 error 事件。当添加新的*时,newListener 事件会触发,当*被移除时,removeListener 事件被触发。

下面我们用一个简单的例子说明 EventEmitter 的用法:

执行结果如下:

运行这段代码,1 秒后控制台输出了 'some_event 事件触发'。其原理是 event 对象注册了事件 some_event 的一个*,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 some_event,此时会调用some_event 的*。

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件*。

当事件触发时,注册到这个事件的事件*被依次调用,事件参数作为回调函数参数传递。

让我们以下面的例子解释这个过程:

执行以上代码,运行的结果如下:

以上例子中,emitter 为事件 someEvent 注册了两个事件*,然后触发了 someEvent 事件。

运行结果中可以看到两个事件*回调函数被先后调用。这就是EventEmitter最简单的用法。

EventEmitter 提供了多个属性,如 onemiton函数用于绑定事件函数,emit属性用于触发一个事件。接下来我们来具体看下 EventEmitter 的属性介绍。

node.js 基础操作

require 函数用来在一个模块中引入另外一个模块。传入一个模块名,返回一个模块导出对象。用法: let cc = require("模块名") ,其中模块名可以用绝对路径也可以用相对路径,模块的后缀名.js可以省略。例如:

require()函数用两个作用:

exports 对象用来导出当前模块的公共方法或属性,别的模块通过 require 函数使用当前模块时得到的就是当前模块的 exports 对象。用法: exports.name ,name为导出的对象名。例子:

mole.exports 用来导出一个默认对象,没有指定对象名,常见于修改模块的原始导出对象。比如原本模块导出的是一个对象,我们可以通过mole.exports修改为导出一个函数。如下:

3.加载第三方包

Node.js中使用 CommonJs 模块化机制,通过 npm 下载的第三方包,我们在项目中引入第三方包都是: let xx = require('第三方包名') ,究竟 require 方法加载第三方包的原理机制是什么,今天我们来探讨下。

require('第三方包名') 优先在加载该包的模块的同级目录 node_moles 中查找第三方包。

找到该第三方包中的 package.json 文件,并且找到里面的 main 属性对应的入口模块,该入口模块即为加载的第三方模块。

如果在要加载的第三方包中没有找到 package.json 文件或者是 package.json 文件中没有 main 属性,则默认加载第三方包中的 index.js 文件。

如果在加载第三方模块的文件的同级目录没有找到 node_moles 文件夹,或者以上所有情况都没有找到,则会向上一级父级目录下查找 node_moles 文件夹,查找规则如上一致。

如果一直找到该模块的磁盘根路径都没有找到,则会报错: can not find mole xxx 。

4.npm命令

npm 英文全称: node package manager ,npm 为你和你的团队打开了连接整个 JavaScript 天才世界的一扇大门。它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(package) (即,代码模块)。来自各大洲的开源软件开发者使用 npm 互相分享和借鉴。包的结构使您能够轻松跟踪依赖项和版本。我们平时开发项目都是需要使用npm下载依赖,常见的npm命令总结如下:

5.文件读取

var fs = require('fs')

同步:

var content = fs.readFileSync('hello.txt',{flag:'r',encoding:"utf-8"})

异步(默认):

flag:读取模式

encoding:编码格式

7.文件写入

var fs = require('fs')

格式:write=>w read=>r append =>a

异步:

8.文件删除

fs . unlink ( 'lc.txt' , function (){

9.buffer缓冲区

1、数组不能进行二进制数据的操作2、js数组不像java、python等语言效率高3、buffer内存空间开辟出固定大小的内存

let buf1 = Buffer.alloc(10)

console.log(buf1)

allocUnsafe(之前的一些内容)(效率高)

10.文件目录

var fs = require('fs')

fs.readdir(path,callback)

导入 readline 包

let readline = require('readline');

实例化接口对象(process对象,stdout/in输入输出)

question方法 提问

close 事件监听

11.文件流

var fs = require('fs')

语法: fs.createWriteStream(文件路径,【可选的配置操作】)

let ws = fs.createWriteStream("hello.txt",{flags:"w",encoding:"utf-8"});

let ws = fs.createWriteStream("hello.txt",{flags:"w",encoding:"utf-8"});

实践

fs.createReadStream(路径,【可选的配置项】)

文档

let rs = fs.createReadStream('hello.txt',{flags:'r',encoding:"utf-8"})

音乐

let rs = fs.createReadStream('snake.mp4',{flags:'r'})

读取时写入

let ws = fs.createWriteStream('a.txt',{flags:"w",encoding:"utf-8"})

createReadStream.pipe(createWriteStream)

链式是通过连接输出流到另外一个流并创建多个流操作链的机制。链式流一般用于管道操作。

接下来我们就是用管道和链式来压缩和解压文件。

创建 compress.js 文件, 代码如下:

代码执行结果如下:

执行完以上操作后,我们可以看到当前目录下生成了 input.txt 的压缩文件 input.txt.gz。

接下来,让我们来解压该文件,创建 decompress.js 文件,代码如下:

12.node事件

Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。

Node.js 几乎每一个 API 都是支持回调函数的。

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。

Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数.

没有使用 events 包 仅使用JavaScript事件监听进行事件驱动

Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。

当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。

这个模型非常高效可扩展性非常强,因为 webserver 一直接受请求而不等待任何读写操作。(这也称之为非阻塞式IO或者事件驱动IO)

在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。

Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:

以下程序绑定事件处理程序:

我们可以通过程序触发事件:

接下来让我们执行以上代码:

在 Node 应用程序中,执行异步操作的函数将回调函数作为最后一个参数, 回调函数接收错误对象作为第一个参数。

接下来让我们来重新看下前面的实例,创建一个 input.txt ,文件内容如下:

创建 main.js 文件,代码如下:

以上程序中 fs.readFile() 是异步函数用于读取文件。如果在读取文件过程中发生错误,错误 err 对象就会输出错误信息。

如果没发生错误,readFile 跳过 err 对象的输出,文件内容就通过回调函数输出。

执行以上代码,执行结果如下:

接下来我们删除 input.txt 文件,执行结果如下所示:

因为文件 input.txt 不存在,所以输出了错误信息。

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。

Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。所有这些产生事件的对象都是 events.EventEmitter 的实例。

events 模块只提供了一个对象:events.EventEmitter。EventEmitter 的核心就是事件触发与事件*功能的封装。

你可以通过require("events");来访问该模块。

EventEmitter 对象如果在实例化时发生错误,会触发 error 事件。当添加新的*时,newListener 事件会触发,当*被移除时,removeListener 事件被触发。

下面我们用一个简单的例子说明 EventEmitter 的用法:

执行结果如下:

运行这段代码,1 秒后控制台输出了 'some_event 事件触发'。其原理是 event 对象注册了事件 some_event 的一个*,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 some_event,此时会调用some_event 的*。

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件*。

当事件触发时,注册到这个事件的事件*被依次调用,事件参数作为回调函数参数传递。

让我们以下面的例子解释这个过程:

执行以上代码,运行的结果如下:

以上例子中,emitter 为事件 someEvent 注册了两个事件*,然后触发了 someEvent 事件。

运行结果中可以看到两个事件*回调函数被先后调用。这就是EventEmitter最简单的用法。

EventEmitter 提供了多个属性,如 onemiton函数用于绑定事件函数,emit属性用于触发一个事件。接下来我们来具体看下 EventEmitter 的属性介绍。

使用Node中的Buffer模块,将图片转换成base64编码

Buffer官方文档如下 http://nodejs.cn/api/buffer.html

node开发过程中,常用的就是将图片转换成base64编码,这时候就用到buffer了:

运行

将打印出来的结果输入到test.js这个文件里,便于查看。之后我们在test.js里就能看到这个图片的base64编码了。

再设置好其 DataURI前缀 就能在浏览器里查看这张图片啦!

下面是我在浏览器查看的结果:

利用Node.js如何实现文件循环覆写

前言

这次编写Node.js项目的时候用到了日志模块,其中碰到了一个小问题。

这是一个定时执行可配置自动化任务的项目,所以输出信息会不断增加,也就意味着日志文件会随时间不断增大。如果对日志文件大小不加以控制,那么服务器的磁盘迟早会被撑满。所以文件大小是有必要的。

最理想的控制方式就是当文件大小超过时,清除最先记录的数据。类似一个FIFO的队列。

# 删除前面的数据

- 1 xxx

......

100 abc

# 文件末尾追加数据

+ 101 xxxx

log4js的file rolling

一提到记录日志很多Node.js开发者肯定会找到log4js,先来看看log4js是怎么处理这个问题的。

log4js分为很多appenders(可以理解为记录日志的媒介),file rolling功能可以通过函数来进行配置。

file rolling功能有两种方式:日期和文件大小。

要控制文件大小,当然选择后者。

为了测试这个功能是否满足我们要求,写一段循环代码来写日志。

const log4js = require('log4js')

// 配置log4js

log4js.configure({

appenders: {

everything: {

type: 'file',

filename: 'a.log',

maxLogSize: 1000,

backups: 0

},

},

categories: {

default: {

appenders: ['everything'],

level: 'debug'

}

}

});

const log = log4js.getLogger();

for (let i = 0; i < 41; i++) {

const str = i.toString().padStart(6, '000000');

log.debug(str);

}

执行之后生成两个文件a.log和a.log.1。

其中a.log.1有20行数据,实际大小1kb,a.log只有1行数据。

虽然确实控制了文件大小,但是会带来两个问题:

额外产生一个备份文件,总占用磁盘空间会超过文件。

日志文件内容的大小是变动的,查询日志的时候很可能需要联合备份文件进行查询(比如上面的情况日志文件只有1行数据)。

推测log4js的实现逻辑可能是下面这样:

检查日志文件是否达到大小,如果达到则删除备份文件,否则继续写入日志文件。

重命名日志文件为备份文件。

这显然不能完全满足需求。

字符串替换?

如果要在内存中完成循环覆写操作就比较简单了,使用字符串或Buffer的即可完成。

添加字符串/Buffer长度,如果超过大小则截取。

写入并覆盖日志文件。

但是有一个很大的问题:占用内存。

比如文件大小为1GB,有10个日志文件同时写入,那么至少占用10GB内存空间!

内存可是比磁盘空间更宝贵的,如此明显的性能问题,显然也不是最优解决方式。

file roll

按照需求可以把实现步骤拆成两步:

追加最新的数据到文件末尾。(Node.js的fs模块有相应函数)

删除文件开头超出部分。(Node.js没有响应函数)

这两步不分先后顺序,但是Node.js没有提供API来删除文件开头部分,只提供了修改文件指定位置的函数。

既然无法删除文件开头部分内容,那么我们就换个思路,只保留文件末尾部分内容(不超出大小)。

什么?这不是一个意思么?

略有区别~

删除是在原有文件上进行的操作,而保留内容可以借助临时文件来进行操作。

所以思路变成:

创建一个临时文件,临时文件的内容来自于日志文件。

往临时文件中增加数据。

将临时文件中符合文件大小的内容,从后往前(采取偏移量的形式)进行读取并复制到日志文件进行覆盖。

为了不占用额外的磁盘空间,写操作完成后删除临时文件。

这样就不会出现像log4js一样日志文件内容不全的现象,也不会保留额外的临时文件。但是对IO的操作会增加~

对于写操作可以采取tail命令来实现,最终实现代码如下:

private write(name: string, buf?: Buffer | string) {

// append buf to tmp file

const tmpName = name.replace(/(.*/)(.*$)/, '$1_.$2.tmp');

if (!existsSync(tmpName)) {

copyFileSync(name, tmpName);

}

buf && appendFileSync(tmpName, buf);

// if busy, wait

if (this.stream && this.stream.readable) {

this.needUpdateLogFile[name] = true;

} else {

try {

execSync(`tail -c ${limit} ${tmpName} > ${name}`);

try {

if (this.needUpdateLogFile[name]) {

this.needUpdateLogFile[name] = false;

this.write(name);

} else {

existsSync(tmpName) && unlinkSync(tmpName);

}

} catch (e) {

console.error(e);

}

} catch (e) {

console.error(e);

}

}

}

总结

完成这个功能有两点感悟:

量变引起质变。当数据量变大时,很多简单的处理方式就不可以用了,比如写文件,如果直接使用writeFile会占用大量内存甚至有可能内存都不够用。所以要通过合适的方式进行拆分,拆分过程中又会碰到各种问题,比如本文中截取文件内容的要求。

学会借力。君子性非异也善假于物也~当无法在单个点完成操作的时候可以借助外部条件来实现,比如在本文中使用临时文件来保存数据内容。

好了,

六三科技网还为您提供以下相关内容希望对您有帮助:

node.js 读写文件的时候可以设置为binary吗

可以设置。读取文件的函数,Node.js 读取文件后,data是以二进制Buffer格式保存的,Blob格式的数据也是以二进制方式保存的,所以可以说data就是题主想要的 Blob binary data,不知道有没有解决题主的问题。var fs = require...

Node.js的Buffer与字符编码及转换

Buffer实例一般用于表示编码字符的序列,如UTF-8、UCS2、Base64或十六进制编码的数据。通过使用显式的字符编码就可以在Buffer实例与普通的JavaScript字符串之间进行相互转换。Node.js目前支持的字符编码包括:●    ...

Buffer简单理解及常用方法介绍

注意:Node.js v0.8 只是简单的引用了array.buffer里的 buffer ,而不是克隆(cloning)。介绍一个高效的方法,ArrayBuffer#slice() 拷贝了一份切片,而 Buffer#slice() 新建了一份。类: Buffer Buffer 类是全局变量类型,...

node.js bufferutil是干什么用的

console.log(new Buffer('68656c6c6f2c20776f726c6421', 'hex').toString());// 还原十六进制字符串:hello, world!一般情况下,单个Node.js进程是有最大内存限制的,以下是来自官方文档中的说明:What is the memory...

nodejs如何把c指针转成buffer

在nodejs里面需要通过socket向C进程发送结构体数据。Buffer 作为 nodejs 中重要的概念和功能,为开发者提供了操作二进制的能力。Buffer 是 nodejs 核心 API,它提供我们处理二进制数据流的功能。Buffer 的使用和 ES2017 的 ...

浅析nodejs的buffer比较怎么比较的

解决方法:(1) 通过可读流中的setEncoding()方法,该方法可以让data事件传递不再是Buffer对象,而是编码后的字符串,其内部使用了StringEncoder模块。(2) 将Buffer对象暂存到数组中,最后在组装成一个大Buffer让后编码转换为...

C语言中buffer到底是什么意思?是数组?缓冲区?为什么一般C程序中都不定...

Buffer是NodeJS的重要数据类型,很有广泛的应用。代表原始堆的分配额的数据类型。在NodeJS中以类数组的方式使用。在Buffer类的描述中,Buffer被定义为用于特定基本类型数据的容器,且是特定基本类型的线性优先元素序列。Buffer...

nodejs去掉图片64编码前面部分

读取图片。1、读取图片文件并将其转换为Buffer对象。2、将Buffer对象转换为字符串,并使用正则表达式去掉前面的编码部分。3、将去掉前面部分的Base64编码字符串转换为Buffer对象。

node.js 基础操作

Node.js中使用 CommonJs 模块化机制,通过 npm 下载的第三方包,我们在项目中引入第三方包都是: let xx = require('第三方包名') ,究竟 require 方法加载第三方包的原理机制是什么,今天我们来探讨下。 require('第三方包名') 优先...

使用Node中的Buffer模块,将图片转换成base64编码

node开发过程中,常用的就是将图片转换成base64编码,这时候就用到buffer了:运行 将打印出来的结果输入到test.js这个文件里,便于查看。之后我们在test.js里就能看到这个图片的base64编码了。再设置好其 DataURI前缀 就能...

本文如未解决您的问题请添加抖音号:51dongshi(抖音搜索懂视),直接咨询即可。

Top