node的文件流的读取和写入

本文详细介绍了Node.js中的文件流,强调了其在处理大文件时的重要性,避免一次性加载到内存中。内容包括如何创建文件流,读取文件流的事件(如open, error, data),以及resume()和pause()的使用。此外,还探讨了文件的写入,特别是以流方式写入的细节,如write()方法与highWaterMark的配合,以及如何监听drain事件实现流写入。最后提到了end()方法用于结束写入。" 120661613,11466485,Halcon初学者的车牌识别实践,"['图像处理', '人工智能', 'Halcon', '车牌识别']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作用

nodeJS中的流最大的作用是:读取大文件的过程中,不会一次性的读入到内存中。每次只会读取数据源的一个数据块。然后后续过程中可以立即处理该数据块(数据处理完成后会进入垃圾回收机制)。而不用等待所有的数据。

这么做的原因:因为浏览器的运行内存一般情况下只有1~3g,倘若我们将一个4g的视频放到浏览器播放,此时浏览器的运行内存便无法去解析了,所以就需要文件流技术了。每次只读取一部分视频,然后运行完成后再销毁,再读取另一段视频,这样便可以完美播放视频了

创建文件流

读取

创建文件流需要利用到require中的fs模块

const fs = require("fs");
const path = require("path");
let filePath=path.resolve(__dirname,"./experiment.txt");//合并路径
fs.createReadStream(filePath,{

})

这样就创建了一个文件流了,通过fs模块的createReadStream函数来操作文件。

    fs.createReadStream(path,[options])
    参数一path :获取文件的路径
    参数二options:可选配置项(用于定义如何操作文件)
    配置项常用属性
	    encoding:编码方式
	    start:起始字节
	    end:结束字节
	    highWaterMark:每次读取的数量(也就是每次读几个字节)
	    autoClose:自动关闭

这样创建之后只是配置了文件流的方式,如果想操作的文件的输出方式的话,需要给它搭载事件

搭载文件流事件
const fs = require("fs");
const path = require("path");
let filePath=path.resolve(__dirname,"./experiment.txt");

let rs = fs.createReadStream(filePath,{
    encoding:"utf-8",
    highWaterMark:3,
    autoClose:true
})

先建立一个变量来接收返回的文件对象。通过rs.on()来给它搭载事件

rs.on()
	常用搭载事件:
    open:  打开的时候运行的事件
    close :关闭的时候运行的事件
    error:  发生错误的时候出发的事件
    data:  获取到一部分数据后触发
    end:所有数据读取完后触发
    pause(): 暂停
    resume(): 继续

举几个例子:
open()事件

const fs = require("fs");
const path = require("path");

let filePath=path.resolve(__dirname,"./experiment.txt");

let rs = fs.createReadStream(filePath,{

})

rs.on("open",()=>{
    console.log("打开文件流");
})

控制台打印
在这里插入图片描述
error()事件

const fs = require("fs");
const path = require("path");

let filePath=path.resolve(__dirname,"./asd/experiment.txt");//路径设置错误

let rs = fs.createReadStream(filePath,{
})

rs.on("open",()=>{
    console.log("打开文件流");
})
rs.on("error", () => {
    console.log("文件出错");
})

控制台打印
在这里插入图片描述
代码中的路径设置错误时,此时不会触发open事件,而是触发error事件

重点:data事件(输出文件内容)

创建文件experiment.txt。它的内容:我是测试文本

注意data事件需要搭配chunk参数,以下data方法的回调函数是箭头函数的缩写

const fs = require("fs");
const path = require("path");

let filePath=path.resolve(__dirname,"./experiment.txt");

let rs = fs.createReadStream(filePath,{
    encoding:"utf-8",
    highWaterMark:3,
    autoClose:true
})

rs.on("data",chunk=>{
    console.log(chunk);
})

控制台打印
注意:现在一个汉字占三个字节
在这里插入图片描述
倘若修改代码:将highWaterMark每次输出的字符修改4个。

let rs = fs.createReadStream(filePath,{
    encoding:"utf-8",
    highWaterMark:4,
    autoClose:true
})

可以看到第三行是两个字,造成这样的原因是因为,highWaterMark设置的是每次输出4个字节,一个汉字占3个字节,第一行只能输出一个汉字,并空出一个字节,第二行补上第一行空出的一个字节,那么此时第二行便空了两个字节,第三行便是2个字节+4个字节,正好输出两个汉字
在这里插入图片描述
多加些汉字:
在这里插入图片描述

resume() 和 pause()

pause():

const fs = require("fs");
const path = require("path");

let filePath=path.resolve(__dirname,"./experiment.txt");

let rs = fs.createReadStream(filePath,{
    encoding:"utf-8",
    highWaterMark:3,
    autoClose:true
})

let amount=0;

rs.on("data",chunk=>{
    if(amount==3){
        rs.pause();
    }
    console.log(chunk);
    amount++;

})

在这里插入图片描述
可以看到在amount=3时,停止输出

resume():
当文件被pause()方法暂停时,可以通过resume()恢复

const fs = require("fs");
const path = require("path");

let filePath=path.resolve(__dirname,"./experiment.txt");

let rs = fs.createReadStream(filePath,{
    encoding:"utf-8",
    highWaterMark:3,
    autoClose:true
})

let amount=0;

rs.on("data",chunk=>{
    console.log(chunk);
        if(amount==3){
            rs.pause();
        }
    amount++;

})

rs.on('pause',()=>{
    rs.resume();
    console.log("恢复了")
})

在这里插入图片描述

写入

关键字:fs.createWriteStream(path,[options])
参数一:文件路径
参数二:可选配置项

flags <string> 参见文件系统 flag 的支持。 默认值: 'w'。(a为在文档的原基础上添加)
encoding <string> 默认值: 'utf8'。
fd <integer> 默认值: null。
mode <integer> 默认值: 0o666。
autoClose <boolean> 默认值: true。
emitClose <boolean> 默认值: false。
start <integer>
fs <Object> | <null> 默认值: null。
highWaterMark 每次写入多少字节

创建一个可写流

const fs=require("fs");
const path=require("path");

let filePath=path.resolve(__dirname,"experiment.txt");

let ws=fs.createWriteStream(filePath,{
});

ws.write("12312");

成功写入
在这里插入图片描述
以上方法是直接将数据写入,只适合小文件写入方式,遇见大文件时我们以流的方式写入更好

以流的方式写入

以流的方式写入时,需要理解write()drain()还有就是配置项中的highWaterMark是怎么和他们配合的。

write()与highWaterMark的配合使用

const fs=require("fs");
const path=require("path");

let filePath=path.resolve(__dirname,"experiment.txt");

let ws=fs.createWriteStream(filePath,{
    highWaterMark:3
});

let i=0;

function flowWrite(){
    let flag=true;
    while(i<9 && flag){
        flag=ws.write("a");
        console.log(flag);
        i++
    }
}

flowWrite();

控制台打印
在这里插入图片描述
文本内容:
在这里插入图片描述

解析:write()在写入数据后,会给一个返回值:根据highWaterMark每次能通过的字节数,如果在写入一个数据后,管道内还有位子,那么返回一个true,否则返回false。

所以上述代码中:

写入第一个a时,highWaterMark规定的通道还有两个字节位子,后面的数据可以直接传输不需要排队,返回true。

写入第二个a时,通道内还有一个字节位子,后面的数据可以直接传输不需要排队,返回true。

写入第三个a时,写入的通道被填满,后面的数据将进入写入队列,返回false。

write()、highWaterMark、drain联合使用,便时流写入了

const fs=require("fs");
const path=require("path");

let filePath=path.resolve(__dirname,"experiment.txt");

let ws=fs.createWriteStream(filePath,{
    highWaterMark:3
});

let i=0;

function flowWrite(){
    let flag=true;
    while(i<10 && flag){
        flag=ws.write("a");
        console.log(flag);
        i++
    }
}

ws.on("drain",()=>{
    console.log("drain执行一次");
    flowWrite();
})

flowWrite();

控制台打印
在这里插入图片描述
文本内容
在这里插入图片描述
可以看到每次false后drain()便执行了一次。由此可以知道drain()可以监听highWaterMark限定的管道通入的宽度。管道被填满后会触发它。

这样便实现了文档流的写入。

另外还有个end()方法

代码执行过程中遇见此方法时,会直接结束写入

const fs=require("fs");
const path=require("path");

let filePath=path.resolve(__dirname,"experiment.txt");

let ws=fs.createWriteStream(filePath,{
    highWaterMark:3
});

let i=0;

function flowWrite(){
    let flag=true;
    while(i<10 && flag){
        flag=ws.write("a");
        console.log(flag);
        i++
    }
}

ws.on("drain",()=>{
    console.log("drain执行一次");
    flowWrite();
})

flowWrite();

ws.end(()=>{
    console.log("杀死进程");
});

控制台
在这里插入图片描述
文本内容
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值