Node.js——I/O流操作

前端基础知识(Node.js) Node.js基础摘要 Node.js是基于Chrome V8引擎的JavaScript运行时环境,核心特性包括非阻塞I/O、事件驱动架构和单线程高性能模型。项目构建通过npm初始化,可安装常用模块如express和http-server。Node.js提供丰富的内置模块如fs(文件系统)、path(路径处理)和http(服务器创建),支持异步回调风格的编程。示例展示了文件读写、HTTP服务创建和时间格式化等基础操作,体现了其服务器端JavaScript开发能力。开发环境建议使用淘宝镜像加速依赖安装。 阅读详情

I/O流,即输入(input)、输出(output)流,它提供了一种向存储设备写入数据和从存储设备读取数据的方式,它是Node.js中执行读写文件操作的一种非常重要的方式。

1、流简介

1.1、流的基本概念

程序中的流是一个抽象概念,当程序需要从某个数据源读取数据时,就会开启一个数据流,数据源可以是文件、内存或者网络等,而当程序将数据写入某个数据源时,也会开启一个数据流,而数据源的目的地也可以是文件、内存或者网络等。

以文件流为例,当需要读取一个文件时,如果使用fs模块的readFile()方法读取,程序会将该文件的内容视为一个整体,为其分配缓存区并一次性将内容读取到缓存区中,在这期间,Node.js将不能执行任何其他处理,这就可能导致一个问题,即如果文件很大,会耗费较多的时间。

如果使用文件流读取文件,则可以将文件一部分一部分地读取,这样可以保证效率,并且不会占用太大的内存。

1.1.1、流的基本类型

Node.js中的流有4种基本类型,分别如下。

  • Readable:可读流。
  • Writable:可写流。
  • Duplex:可读可写流(也称双工流)​。
  • Transform:转换流,表示在读写过程中可以修改和变换数据的Duplex流。
1.1.2、流模块的引用

使用Node.js中的流之前,首先要引用stream模块,代码如下:

const stream = require('stream');

1.2、Buffer

Buffer就是开辟的一块内存区域,Buffer的大小就是开辟的内存区域的大小。在流中,Buffer的大小取决于传入流构造函数的highWaterMark选项参数,该参数指定了字节总数或者对象总数,当可读缓冲区的总大小达到highWaterMark指定的阈值时,流会暂时停止从数据源读取数据,直到当前缓冲区的数据被释放;如果要获取缓冲区中存储的数据,需要使用writable.writableBuffer或readable.readableBuffer。

2、可读流的使用

2.1、流的读取模式与状态

2.1.1、可读流的读取模式

可读流有两种读取模式,即流动(flowing)模式和暂停(paused)模式。

所有的可读流都是以暂停模式开始,当流处于暂停模式时,可以通过read()方法从流中按需读取数据。

流动模式指的是一旦开始读取文件,会按照highWaterMark的值按次读取,直到读取完为止。当流处于流动模式时,因为数据是持续变化的,所以需要使用监听事件来处理它。

流的暂停模式和流动模式是可以互相切换的,如通过添加data事件、使用resume()方法或者pipe()方法等都可以将可读流从暂停模式切换为流动模式;使用paused()方法或者unpipe()方法可以将可读流从流动模式切换为暂停模式。

2.1.2、可读流的状态

在实际使用可读流时,它一共有3种状态,即初始状态(null)、流动状态(true)和非流动状态(false)。

当流处于初始状态(null)时,由于没有数据使用者,所以流不会产生数据,这时如果监听data事件、调用pipe()方法或resume()方法,都会将当前状态切换为流动状态(true),这样可读流即可开始主动地产生数据并触发事件。

如果调用pause()方法或者unpipe()方法,就会将可读流的状态切换为非流动状态(false),这将暂停流,但不会暂停数据生成。此时,如果再为data事件设置监听器,就不会再将状态切换为流动状态(true)了。

2.2、可读流的创建

Node.js中的可读流使用stream模块中的Readable类表示,因此可以直接使用下面代码创建:

const readable = new stream.Readable();

另外,还可以使用fs模块的createReadStream方法创建可读流,语法格式如下:

fs.createReadStream(path[, options])
  • path:读取文件的文件路径,可以是字符串、缓冲区或网址。
  • options:读取文件时的可选参数,可选值如下。
    • flags:指定文件系统的权限,默认为r。
    • encoding:编码方式,默认为null。
    • fd:文件描述符,默认为null。
    • mode:设置文件模式,默认为0o666。
    • autoClose:文件出错或者结束时,是否自动关闭文件,默认为true。
    • emitClose:流销毁时,是否发送close事件,默认为true。
    • start:指定开始读取的位置。
    • end:指定结束读取的位置。
    • highWaterMark:可读取的阈值,一般设置在16~100KB范围内。
const fs = require("fs");
const read = fs.createReadStream("春夜喜雨.txt");

2.3、可读流的属性 方法及事件

可读流提供了很多属性、方法和事件,用来获取可读流信息、对可读流进行操作,以及监听可读流的相应操作,如下表:

常用属性:

属性说明
destroyed可读流是否已销毁,如果已经调用了readable.destroyO方法,则该属性值为true
readable可读流是否被破坏、结束或者报错
readableEncoding获取可读流的encoding属性
readableEnded可读流是否已经没有数据,如果触发了end事件,则该属性值为rue
readableFlowing可读流的当前状态
readableHighWaterMark构造可读流时传入的high WaterMark的值
readableLength获取准备读取的队列中的字节数(或对象数)

常用方法:

方法说明
read([sizel)从流中读取数据
setEncoding(encoding)设置从流中读取的数据所使用的编码
pause()暂停从可读流对象发出的data事件
ispaused()获取可读流的当前操作状态
destroy()销毁可读流
resume()恢复从可读流对象发出的data事件
pipe(destination[,options])把可读流的输出传输到一个由deatination参数指定的Writable流对象
unpipe([destinationl)分离附加的Writale流对象
filter(fn[,options])筛选流
forEach(fn[,options])迭代遍历流

常用事件:

事件说明
close当流或其数据源被关闭时,触发该事件
data在流将数据块传送给使用者后触发
end当流中没有数据可供使用时触发
error当流由于底层内部故障而无法生成数据或尝试推送无效数据块时触发
pause当调用stream.pause().且readsFlowing不为false时触发
readable当有数据可从流中读取时触发
resume当调用stream.resume().且readsFlowing不为true时触发

触发流事件同样采用on()方法实现,例如,下面代码创建了一个可读流,然后触发其data事件:

const fs = require("fs")
let read = fs.createReadStream('春夜喜雨.txt')
read.on('data', (chunk)=>{
    console.log("读取到的数据:" + chunk.toString());
})
读取到的数据:  春夜喜雨
          杜甫
好雨知时节,当春乃发生。
随风潜入夜,润物细无声。
野径云俱黑,江船火独明。
晓看红湿处,花重锦官城。

2.4、可读流的常见操作

2.4.1、读取数据

使用read()方法可以从流中读取数据,其语法格式如下:

对象名.read([size])
  • size:要读取的数据的字节数。
  • 返回值:返回值可能为字符串、Buffer、null等。
const fs = require("fs");
const read = fs.createReadStream("春夜喜雨.txt", {encoding: 'utf-8'});
read.on('readable', ()=>{
     while (null !== (chunk = read.read(25))) {
          console.log(chunk.toString());
     }
});
2.4.2、设置编码格式

可读流读取数据时,默认情况下没有设置字符编码,流数据返回的是Buffer对象。如果设置了字符编码,则流数据返回指定编码的字符串。设置可读流中数据的编码格式需要使用setEncoding()方法,其语法格式如下:

对象名.setEncoding(encoding)
const fs = require("fs");
const read = fs.createReadStream("春夜喜雨.txt");
read.setEncoding("utf8")                       //设置编码格式
read.on('readable', function () {
     while (null !== (chunk = read.read(25))) {
        //设置编码格式后,此处不再需要使用toString()方法
        console.log(chunk);
     }                
});
        春夜喜雨
          杜甫
好雨知时节,当春乃发生。

随风潜入夜,润物细无声。
野径云俱黑,江船火独明。

2.4.3、 暂停与恢复流

pause()方法可以使流动模式的可读流停止触发data事件,并切换为非流动模式,其语法格式如下:

对象名.pause()

resume()方法可以恢复从可读流对象发出的data事件,将可读流切换为流动模式,其语法格式如下:

对象名.resume()

按行输出故事内容:

const fs = require('fs');
const read= fs.createReadStream("春夜喜雨.txt", {highWaterMark: 25});
read.setEncoding("utf8")                       //设置编码格式
read.on('data', (chunk)=>{
     console.log(chunk.toString());
     read.pause();
     setTimeout(()=>{
          read.resume();
     }, 1000);
});
read.on("close",()=>{
     console.log("读取完毕");
})
2.4.4、 获取流的运行状态

对可读流进行操作时,可以使用ispaused()方法判断流当前的操作状态,该方法不需要参数,返回结果为true或false,其语法格式如下:

对象名.ispaused()
const readable = new stream.Readable();
console.log(readable.ispaused());
readable.pause()
console.log(readable.ispaused());
false
true

ispaused()方法主要用于readable.pipe()底层的机制,大多数情况下不会直接使用该方法。

2.4.5、 销毁流

使用destroy()方法可以销毁可读流,其语法格式如下:

对象名.destroy([error])

该方法中有一个可选参数error,用于在处理错误事件时发出错误。

const fs = require("fs")
const read = fs.createReadStream('春夜喜雨.txt')
read.setEncoding("utf8")
read.on('data', function (chunk) {
     console.log("读取到的数据:\n" + chunk.toString());
})
read.destroy()

上面代码运行结果为空,因为最后一行代码销毁了可读流read,可读流在销毁后,会将读取的数据清空,因此,通常在程序可能出现异常时,才会在处理异常的过程中使用销毁流方法。

2.4.6、 绑定可写流至可读流

readable.pipe()方法可以将可写流绑定到可读流,并将可读流自动切换到流动模式,同时将可读流的所有数据推送到绑定的可写流。pipe()方法的语法格式如下:

可读流对象名.pipe(destination[, options])
  • destination:要绑定到可读流的可写流对象。
  • options:保存管道选项,通常为end参数,其参数值为true,表示如果可读流触发end事件,可写流也调用steam.end()结束写入,如果设置end值为false,则目标流就会保持打开。
  • 返回值:返回目标可写流。

pipe的含义为管道,比如要从A桶中向B桶中倒水,如果直接用A桶来倒水,那么水流可能会忽大忽小,而B桶中的水有可能因为溢出或者来不及使用而浪费,那么如何让水不浪费呢?这时就可以用一根水管连接A桶与B桶,这样A桶中的水通过水管匀速地流向B桶,B桶中的水就可以及时使用而不会造成浪费。流中的pipe也是如此,它是连接可读流和可写流的一条管道,可以实现读取数据和写入数据的一致性。这里需要说明的是,pipe()是可读流的方法,只能将可写流绑定到可读流,反之则不可以。

通过将可写流绑定至可读流为文件追加内容。

const fs = require("fs");
const read = fs.createReadStream('春夜喜雨.txt');                    //创建可读流
const write = fs.createWriteStream('aaa.txt', {flags: "a"});  //创建可写流
read.pipe(write);                                              //将可写流绑定到可读流
console.log("已完成")
2.4.7、 解绑可写流

上文讲解了使用可读流的pipe()方法可以将可写流绑定到可读流,还可以通过可读流的unpipe()方法将已经绑定的可写流进行解绑,其语法格式如下:

可读流对象名.unpipe([destination])

该方法中有一个可选参数destination,表示要解绑的可写流,如果该参数省略,表示解绑所有的可写流。

const fs = require("fs");
const read = fs.createReadStream('春夜喜雨.txt');                    //创建可读流
const write = fs.createWriteStream('bbb.txt', {flags: "a"});  //创建可写流
read.pipe(write);                                              //将可写流绑定到可读流
console.log("已绑定可写流")
read.unpipe(write)                                             //解绑
console.log("已解绑可写流")

上面代码先为可读流read绑定一个可写流write,这时春夜喜雨.txt文件中的内容都被追加到“bbb.txt”文件中,然后将write解绑,于是从“bbb.txt”文件中移除春夜喜雨.txt中的内容,最终“凉州词.txt”文件中的内容将不会发生变化。

3、可写流的使用

3.1、可写流的创建

Node.js中的可写流使用stream模块中的Writable类表示,使用该类时,需要重写其中的write()方法,因此要使用stream模块中的Writable类创建可写流,需要使用的代码类似下面代码:

const stream = require('stream');
const writable = new stream.Writable({
     write: function (chunk, encoding, next) {
          console.log(chunk.toString());
          next();
     }
});

另外,还可以使用fs模块的createWriteStream()方法创建可写流,语法格式如下:

fs.createWriteStream(path[, options])
  • path:写入文件的文件路径。
  • options:写入文件时的可选参数,可选值如下。
    • flags:指定文件系统的权限,默认为w,如果要修改文件内容,而不是替换,需要将该值设置为a。
    • encoding:编码方式,默认为null。
    • fd:文件描述符,默认为null。
    • mode:设置文件模式,默认为0o666。
    • autoClose:文件出错或者结束时,是否自动关闭文件,默认为true。
    • emitClose:流销毁时,是否发送close事件,默认为true。
    • start:指定开始写入的位置。
    • highWaterMark:可写入的阈值,一般设置在16~100KB范围内。
var fs = require("fs");
var write = fs.createWriteStream('demo.txt');  //创建可写流

3.2、可写流的属性 方法及事件

可写流提供了很多属性、方法和事件,用来获取可写流信息、对可写流进行操作,以及监听可写流的相应操作,它们的说明分别如表所示。

常用属性:

属性说明
destroyed可写流是否已销毁,如果已经调用了writable.destroy(),则为true
writable可写流是否被破坏、报错或结束
writableEnded可写流是否已经没有数据,如果在调用writable.end()之后,该值为rue
writableCorked获取完全uncork流需要调用writable.uncork()的次数
writableFinished可写流中的数据是否已传输完,在触发finish事件之前需将其设置为true
writableHigh WaterMark返回构造可写流时传入的high WaterMark的值
writableLength包含准备写入的队列中的字节数(或对象)
writableNeedDrain如果流的缓冲区已满且流将发出drain,则为true

常用方法:

方法说明
write()写入数据
end()通知可写流对象写入结束
setDefaultEncoding为可写流设置默认的编码方式
end()关闭可写流
destroy()销毁可写流
cork()强制把所有写入的数据都缓冲到内存中
uncork()将调用stream.cork0方法缓冲的所有数据输出到目标

常用事件:

事件说明
close当可写流或数据源被关闭时,触发该事件
open创建可写流的同时会打开文件,而打开文件就会触发该事件
drain当写入缓冲区为空时触发该事件
error写入或管道数据发生错误时触发该事件
finish调用stream.end()且缓冲区数据都已传给底层系统之后触发该事件
pipe当在可读流上调用stream.pipe()方法时会触发该事件,并将此可写流添加到其目标集
unpipe在可读流上调用stream.unpipeO方法时会触发该事件,从其目标集中移除此可写流

3.3、可写流的常见操作

3.3.1、写入数据

使用write()方法可以向流中写入数据,其语法格式如下:

对象名.write( chunk[, encoding, callback])
  • chunk:要写入的数据,其值可以是字符串、缓冲区或数组等。
  • encoding:可选参数,表示写入数据时的编码方式。
  • callback:可选参数,是一个回调函数,写入数据完成后执行。
const fs = require("fs")
let txt = "这首诗抓住了边塞风光景物的一些特点,借其严寒春迟及胡笳声声来写战士们的心理活动,反映了边关将士的生活状"
    + "况。诗风苍凉悲壮,但并不低沉,以侠骨柔情为壮士之声,这仍然是盛唐气象的回响。"
//在文件原有内容后面追加内容,所以定义文件权限为“a”
let decr = fs.createWriteStream("凉州词.txt", {flags: "a"})
decr.write("\n鉴赏:\n" + txt, "utf8")                     //写入内容
3.3.2、设置编码方式

使用setDefaultEncoding()方法可以设置可写流的默认编码方式,其语法格式如下:

对象名.setDefaultEncoding(encoding)
  • 参数encoding表示要设置的编码方式。
const fs = require("fs")
const writeSteam = fs.createWriteStream("demo.txt")
writeSteam.setDefaultEncoding("utf8")              //设置编码方式
writeSteam.write("测试数据")                       //写入内容
3.3.3、关闭流

写入流的end()方法用来标识已经没有需要写入流中的数据了,因此通常用来关闭流,其语法格式如下:

对象名.end([chunk[, encoding]][, callback])
  • chunk:可选参数,表示关闭流之前要写入的数据。
  • encoding:如果chunk为字符串,那么encoding为编码方式。
  • callback:流结束或者报错时的回调函数。
const fs = require("fs")
const writeSteam = fs.createWriteStream("demo.txt")
writeSteam.setDefaultEncoding("utf8")              //设置编码方式
writeSteam.write("测试数据")                       //写入内容
writeSteam.end("写入完成")                         //关闭流
//writeSteam.write('继续写入');
测试数据
写入完成

使用end()方法关闭流后,无法再向流中写入数据,否则将会产生异常,例如,去掉上面代码中最后一行的注释,再次运行时,将会出现错误提示。

3.3.4、销毁流

使用destroy()方法可以销毁所创建的写入流,并且流被销毁后,无法再向流写入数据。其语法格式如下:

对象名.destroy([error])
  • 参数error为可选参数,表示使用error事件触发的错误。
const fs = require("fs")
const writeSteam = fs.createWriteStream("demo.txt")
writeSteam.setDefaultEncoding("utf8")              //设置编码方式
writeSteam.write("测试数据")                       //写入内容
writeSteam.destroy()                               //销毁流

上面代码运行后,将会导致demo.txt文件中没有任何数据,因为虽然第4行代码中使用write()方法写入了数据,但由于紧接着销毁了写入流,这将导致使用该流执行的任何操作都会失效。因此,在使用写入流销毁操作时,通常在异常处理中使用该操作。

3.3.5、将数据缓冲到内存

使用写入流的cork()方法可以强制把所有写入的数据都缓冲到内存中,它的主要目的是为了适应将几个数据快速连续地写入流的情况。cork()方法不会立即将它们转发到底层目标处,而是缓冲所有数据块,直到调用uncork()方法。cork()方法的语法格式如下:

对象名.cork()

当使用uncork()方法或end()方法时,缓冲区数据将被刷新。

const stream = require('stream');
const writable = new stream.Writable({
     write: function (chunk, encoding, next) {
          console.log(chunk.toString());
          next();
     }
});
writable.write('天气晴朗');
writable.cork();
writable.write('阳光明媚');
天气晴朗

通过观察上面结果,发现调用cork()方法后,接下来要输出的内容并没有显示。

3.3.6、输出缓冲后的数据

前面介绍了cork()方法,用以强制把所有写入的数据都缓冲到内存中,而使用uncork()方法可以将调用cork()方法后缓冲的所有数据输出到目标处。uncork()方法的语法格式如下:

对象名.uncork()
const stream = require('stream');
const writable = new stream.Writable({
     write: function (chunk, encoding, next) {
          console.log(chunk.toString());
          next();
     }
});
writable.write('天气晴朗');
writable.cork();
writable.write('阳光明媚');
writable.uncork();
天气晴朗
阳光明媚

4、双工流与转换流

4.1、双工流

双工流Duplex可以实现流的可读和可写功能,即同时实现Readable和Writable。实现双工流需要进行以下3步。

  1. 继承Duplex类。
  2. 实现_read()方法。
  3. 实现_write()方法。
const Duplex = require('stream').Duplex;
const myDuplex = new Duplex({
     _read(size) {
          // ...
     },
     _write(chunk, encoding, callback) {
          // ...
     }
});

示例:双工流的使用

const stream = require('stream');
const duplexStream = stream.Duplex();
duplexStream._read = function () {
     this.push('读取数据');
     this.push(null)
}
duplexStream._write = function (data, enc, next) {
     console.log(data.toString());
     next();
}
duplexStream.on('data', data => console.log("监听:" + data.toString()));
duplexStream.on('end', data => console.log('监听:' + '读取完成'));
duplexStream.write('写入数据');
duplexStream.end();
duplexStream.on('finish', data => console.log('监听:' + '写入完成'));
写入数据
监听:读取数据
监听:写入完成
监听:读取完成

4.2、转换流

转换流Transform其实也是双工流,它与Duplex的区别在于,Duplex虽然同时具备可读流和可写流的功能,但两者是相对独立的,而Transform中可读流的数据会经过一定的处理过程自动进入可写流。需要说明的是,从可读流到可写流,它们的数据量不一定相同。例如,常见的压缩、解压缩用的zlib就使用了转换流,压缩和解压缩前后的数据量明显不同。

实现转换流需要进行以下两步:

  1. 继承Transform类。
  2. 实现_transform()方法。_transform()方法用来接收数据,并产生输出(需要调用this.push(data),如果不调用,则接收数据但不输出)​。当数据处理完后,必须执行callback(err, data)回调函数,该函数中的第一个参数用于传递错误信息,第二个参数用来输出数据(效果和this.push(data)相同)​,但参数可以省略。
const Stream = require('stream')
class TransformReverse extends stream.Transform {
     constructor() {                               //继承构造函数
          super()
     }
     _transform(data, encoding, callback) {
          this.push(data);
          callback();
     }
}

示例:转换流的使用

const Stream = require('stream');
class TransformStream extends Stream.Transform {
     constructor() {
          super()
     }
     _transform(data, encoding, callback) {
          //将写入的数据进行反转
          const res = data.toString().split('').reverse().join('');
          this.push(res)                                 //输出反转后的数据
          callback()
    }
}
var transformStream = new TransformStream();
transformStream.on('data', data => console.log(data.toString()))
transformStream.on('end', data => console.log('读取完成'));
transformStream.write('写入数据');
transformStream.end()
transformStream.on('finish', data => console.log('写入完成'));
据数入写
读取完成
写入完成
【Node.js从基础到高级运用】十七、Node.js的性能优化 性能优化是一个需要不断学习和实践的过程。在Node.js中,优化I/O操作是提高性能的关键。通过异步I/O、流和管道、缓存等技术,我们可以显著提升应用的响应速度和处理能力。同时,使用性能监控工具如Node Clinic和0x,可以帮助我们更好地理解和分析性能瓶颈。 阅读详情

相关推荐

TDSQL-单机安装

根据腾讯云官方要求,TDSQL安装至少需要三台机器。本人想要学习TDSQL但是没有足够的机器资源,经过仔细分析研究TDSQL安装过程,尝试发现单台机器也可以成功安装TDSQL,现将本人单台机器安装TDSQL的过程以及安装过程中遇到的问题在此分享。具体安装过程可参考腾讯官方文档,本文仅分享与官方文档不一致的步骤。

u012607648的博客 6809

NodeJs 第三章 文件I/O、文件流

流是指数据的流动,数据从一个地方缓缓的流动到另一个地方流是有方向的可读流: Readable(数据从源头流向内存)可写流: Writable(数据从内存流向源头)双工流:Duplex(数据即可从源头流向内存又可从内存流向源头)为什么需要流其他介质和内存的数据规模不一致其他介质和内存的数据处理能力不一致。

aXin_li的博客 1262

LabVIEW 调用MATLAB 进行图像处理的实现

程机械及设备的变形、振动、冲击、粗糙度、刚度和强度等特性,还可用在土木结构、水利设施的变形测量[4][5]。因此,该技术在机械、土木、水利、电器、航空航天、兵器工业及生物医学等领域的检测中具有非常重要的地位。将物面前方空间的散斑用摄像设备记录下来,当物体运动或由于受力而变形时,这些随机分布的散斑图也随之在空间按一定的规律运动,因此能用记录的散斑图在计算机上分析物体的运动和变形,这就是电子散斑技术。当物体的漫反射表面被激光照射时,漫反射的光波在物体表面的前方相互干涉,由于漫反射光的。

qq_37971227的博客 3874

Nodejs 异步I/O

学习 Node 异步编程,了解大型项目用 Node 作为中间层思想原理。

SK_study的博客 2128

RiscV运行zephyr和Linux的方法

riscv基金会搞了一个网站,用于介绍如何使用riscv指令集进行开发。 对于运行zephyr和linux以及Qemu有非常大的帮助。 可以作为riscv开发的相关参考。 RISC-V - Getting Started Guide — RISC-V - Getting Started Guidehttps://risc-v-getting-started-guide.readthedocs.io/en/latest/index.html RISC-V - Getting Started Gu.

闲人的专栏 737

PID不够用?试试给PID加上‘预言’能力:史密斯预测器(SP)在温控、液位控制中的实战配置

本文深入探讨了史密斯预测器(SP)在温控和液位控制中的应用,特别针对大滞后系统的PID控制难题。通过详细解析SP的核心组件、参数整定技巧及进阶应用FSP,结合西门子PLC的实战配置方案,帮助工程师有效提升控制精度和系统稳定性。文章还提供了S7-1200的完整实现步骤和调试技巧,为工业自动化控制提供了实用解决方案。

weixin_33686714的博客 469

nodejs单线程?非阻塞I/O?异步?

一、多线程与单线程 像java、python这个可以具有多线程的语言。多线程同步模式是这样的,将cpu分成几个线程,每个线程同步运行。 而node.js采用单线程异步非阻塞模式,也就是说每一个计算独占cpu,遇到I/O请求不阻塞后面的计算,当I/O完成后,以事件的方式通知,继续执行计算2。 事件驱动、异步、单线程、非阻塞I/O,这是我们听得最多的关于nodejs的介绍。看到上面的关键字,可能我们会好奇: 为什么在浏览器中运行的 Javascript 能与操作系统进行如此底层的交互? nodejs既然是

githubcurry,985cs博士在读 1655

MATLAB实战:用Costas环和Gardner环搞定QPSK同步问题(附完整代码)

本文详细介绍了如何使用MATLAB实现Costas环和Gardner环联合解决QPSK同步问题,包括载波同步和定时同步的技术原理、MATLAB代码实现及性能分析。通过完整的仿真示例和工程实践建议,帮助读者掌握QPSK同步技术的核心要点,提升数字通信系统的解调性能。

agile9scrum的博客 691

Nodejs - 异步I/O

从JavaScript中调用node 的核心模块,核心模块中调用c++内建模块,内建模块通过libuv进行系统调用,这里的libuv作为封装层,有两个平台的实现,实际上是调用了uv_fs_open()的方法,在uv_fs_open()的调用过程中,创建了一个FSReqWrap请求对象,从JavaScript传入的参数和当前方法都被封装在这个请求对象中,最为关注的回调函数则被设置在这个对象的oncomplete_sym属性上。就会进行休眠,知道事件将它唤醒,利用事件通知,执行回调的方式,而不是遍历查询。

m0_73280507的博客 1164

【YOLO26实战全攻略】10——YOLO26+SAM3实战:从检测到像素级分割的全流程指南(含PCB缺陷检测案例)

本文聚焦YOLO26与SAM3的融合应用,系统讲解“检测+分割”的三种核心模式:YOLO26原生分割(轻量高效)、YOLO26检测+SAM3精细分割(精度极致)、SAM3自动标注+YOLO26蒸馏(低成本冷启动)。从环境搭建、数据集准备、模型训练、性能优化到边缘部署,提供 step-by-step 实操教程,配套完整可运行代码与执行结果。结合虚拟PCB缺陷检测案例,展示像素级缺陷识别与几何参数测量的工业级应用流程。本文兼顾新手入门与进阶提升,注重实用价值,读者可直接参考搭建自己的分割系统。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 626

基于YOLOv10的微小目标检测,多头检测器提升小目标检测精度

引入多头检测器助力YOLOv10,暴力提升小目标检测性能

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 2569

深入剖析Nodejs的异步IO

前言:Nodejs最赖以自豪的优势莫过于“单线程实现异步IO”了,也许你仍然丈二和尚摸不着头脑,Nodejs自我标榜是单线程,还能实现异步IO操作,这两者难道不是相互矛盾的么?葫芦里到底藏着什么药? 且听我娓娓道来……一、首先,看看Nodejs的架构图http://nodejs.cn/download/ 你可以到Nodejs中文网下载Node源码。Nodejs结构大体分为三个部分:1)Nod

小小石头的那些事儿 1万+

大疆RoboMaster嵌入式面试,电机FOC调不出来当场走人

摘要:大疆RoboMaster嵌入式工程师面试以实战能力著称,重点考察FreeRTOS任务调度、FOC电机控制和CAN总线三大核心技能。FreeRTOS部分涉及优先级调度、栈溢出排查及信号量与互斥锁的区别;FOC控制要求现场编写电流环代码,并解释Clarke/Park变换原理;CAN总线则关注仲裁机制、CANopen协议应用及错误帧排查方法。面试强调工程实践,需具备STM32开发经验,建议搭建实际环境进行练习。该岗位被誉为"硬件版修罗场",充分体现大疆对实际开发能力的严格要求。

郑伟强dev的专栏 150

Node.js流基础:高效处理I/O操作的核心技术

Node.js中的流受到Unix管道的启发,提供了一种以流式方式从源读取数据并将其传输到目标的机制。简单地说,流就是一个EventEmitter,并实现了一些特殊方法。根据实现的方法,流可以是可读、可写、双工或转换。

分享技术点滴 443

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

node-01-了解及基本操作

node 官方: 基于 Chrome V8 引擎的 javascript 运行时环境 私人: 一个 "软件", 能运行 JS 代码 解析引擎 前端: JS 三大核心 => DOM 文档对象模型: 因为你的 JS 是被引入再 html 文件里面 => BOM 浏览器对象模型: 因为你的 JS 是被运行再 浏览器 里面的 -> 需要用到浏览器的内核中的 解析引擎 来解析 js 文件执行 => ECMAScript 语法: JS 的语法标准 n

qq_36158581的博客 170

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【Node.js】stream 流

流是一种抽象的数据结构。从键盘输入到应用程序就是标准输入流(stdin)。应用程序把字符一个一个输出到显示器上叫做:标准输出流(stdout)。流的特点是数据是有序的,而且必须依次读取,或者依次写入,不能像Array那样随机定位。以 Buffer 作为传输单位。它不像传统的程序那样一次将一个文件读入内存,而是逐块读取数据、处理其内 容,而不是将其全部保存在内存中。流可以分成三部分:source、 dest、 pipe。

小秀的博客 896

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

常见的node.js面试题

什么是Node.js?它的优点是什么? Node.js是一个基于Chrome V8引擎的JavaScript运行时,用于构建可伸缩的网络应用程序。它的优点包括高效的I/O操作、事件驱动的非阻塞I/O模型、可重用的代码库、易于学习和使用等。 Node.js中的事件循环是什么?它是如何工作的? 事件循环是Node.js中的核心机制之一,它用于处理异步I/O操作。事件循环会不断地检查事件队列,如果队列中有事件,就会取出一个事件并执行对应的回调函数。如果队列为空,事件循环会进入休眠状态,等待新的事件加入队列。 什么

m0_63096587的博客 264

Node.js

用libuv进行异步I/O操作 用event loop 管理事件处理顺序 用C/C++库高效处理DNS/HTTP… 用bindings让JS能和C/C++沟通 用V8运行JS 用Node.js标准库简化JS代码

JankoY的博客 170

Node.js菜鸟教程 思维导图

Node.js菜鸟教程思维导图 1 介绍 简单的说 Node.js 就是运行在服务端的 JavaScript。 Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。 Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非...

南方有乔木的博客 1756

深入理解 Node.js Stream:高效处理大文件和数据流

Stream(流) 是 Node.js 提供的高效数据处理机制,它可以在不占用大量内存的情况下,以分块(chunk)的方式流式处理数据,适用于大文件处理、实时数据传输、日志处理等场景。 本篇文章将从 基础概念 到 实战案例,深入讲解 Node.js Stream 流式处理 的原理及应用,帮助你提升 I/O 操作的效率。

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 1481

【Node】Node.js 入门知识点总结(一)

一、Node.js 回调函数 Node.js 异步编程的直接体现就是回调函数。 Node 所有 API 都支持回调函数。 回调函数一般作为函数的最后一个参数出现。 例如,我们可以一边读取文件,一边执行其他命令,在文件读取完成后,我们将文件内容作为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操作。这就大大提高了 Node.js 的性能,可以处理大量的并发请求。 二、No...

Dora_5537的博客 671

Node.js 设计模式 学习笔记 之 流编程

参考 《Node 设计模式2》 【译】 Node.js 流: 你需要知道的一切 1. 什么是流? 不同于缓冲,流可以读取数据的一部分同时立即提供给后序处理,这提高了内存的空间效率和程序运行的时间效率。 缓冲的内存空间问题:缓冲是一次性读取所有数据到内存,然后才能交给处理程序,如果文件数据过大比如由几百MB甚至几百GB,那么读取整个文件到缓冲,然后再一次下返回,那么可能会导致内存溢出(比如说在 ...

weixin_33795833的博客 161

Node.js基础学习2

Node.js Buffer缓冲区JavaScript语言自身只要字符型数据类型,没有二进制数据类型。但是在处理像TCP流或文件流时,必须使用到二进制数据。因此在Node.js中,定义了一个Buffer类,该类用来创建一个专门存放二进制数据的缓存区。Buffer库为Node.js带来了一种存储原始数据的方法,可以让Node.js处理二进制数据,每当需要在Node.js中处理I/O操作中移动的数据时,

岛上书店 512

Node.js入门教程(十八):Stream(流)

高效处理流式数据,节省内存提升性能

Smell_of_earth的博客 533

Node基础:基础API

一、处理I/O 1.异步非阻塞I/O 关于上述概念,网上有一个很经典的响水壶解释 隔壁王大爷有个水壶,王大爷经常用它来烧水。 (同步阻塞):王大爷把水壶放到火上烧,然后啥也不干,就在那等,直到水烧开了王大爷再去干别的事情。 (同步非阻塞):王大爷觉得自己有点憨,不打算等了,把水壶放上去之后就去看剧了,时不时来瞅一眼水有没有开。 (异步阻塞):王大爷去买了响水壶,他把壶放到火上,然后也是等着水开,水开的时候水壶会发出声响。 (异步非阻塞):王大爷觉得有点憨,他把水壶放到火上然后去看剧,也不用时不时瞅一眼,因为

imagine_tion的博客 251

前端菜鸟查漏补缺--node.js篇(上篇)

关于node.js。我再前面项目中使用webpack搭建项目的时候有了解过。当时单纯只是说配置webpack和vue的时候需要。而没有真正的把它作为一个新的知识点来学习。其实现在node.js对于前端来说还是蛮重要的,还是要慢慢学习啊。 ...

weixin_45101949的博客 436
上一篇: Node.js——异步编程与回调
下一篇: Node.js——Web相关模块
吴声子夜歌
博客等级 码龄9年 2688粉丝 2269原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值