nodeJS文件流和事件

1. 普通文件拷贝

文件拷贝的原理是通过fs.readFile从一个文件读取内容,然后通过fs.writeFile将其写入另一个文件。

readFile会默认将文件内容全部读取到内存中,然后再写入另一个文件。

let fs = require(‘fs‘); //fs即file system
let path = require(‘path‘);
/*
1. 读取文件使用绝对路径;
2. 读取的内容全部读取到内存中;
*/
// 异步读取文件
fs.readFile(path.resolve(__dirname, ‘./1.txt‘), (err,data) => {
  // 写入文件;如果对应路径上文件不存在,会自动创建一个文件
  fs.writeFile(path.resolve(__dirname, ‘./2.txt‘), data, (err) => {
    console.log("写入成功");
  });
})

但是这种拷贝文件的方式,适用与文件较小时(小于64k)。当大于64k时,会出现性能问题。通常会希望文件边读边写。

这就需要文件流。

2. 事件模块events

文件流基于事件。

// 手动实现一个events模块 模拟let EventEmitter = require(‘events‘);
class EventEmitter{
  constructor() {
    // {eventName: [callback1, callback2],....}
    this._events = {};
  }
  // 订阅
  on(eventName, callback) {
    if(this._events[eventName]) {
      this._events[eventName].push(callback);
    } else {
      this._events[eventName] = [callback];
    }
  }
  // 发布
  emit(eventName) {
    this._events[eventName].forEach(fn => {
      fn();
    });
  }
  // removeListener
  off(eventName, callback) {
    this._events[eventName] = this._events[eventName].filter(fn => fn !== callback)
  }
}

// 应用
const e = new EventEmitter();

let eatFood = () => {
  console.log(‘eat food‘);
}
let eatFruit = () => {
  console.log(‘eat fruit‘);
}
e.on(‘eat‘, eatFood);
e.on(‘eat‘, eatFruit);

e.emit(‘eat‘);
/*
eat food
eat fruit
*/
e.off(‘eat‘, eatFood);
e.emit(‘eat‘);
// eat fruit

3. 文件流

fs模块提供了流操作的API。

流分为四类:可读流、可写流、双工流(可读可写)、转换流(压缩文件)

1. 可读流

可读流的作用:

 1. 可以分段读取文件
 2. 可以控制读取的速率和范围

可读流主要依赖于fs.createReadStream()方法。 实例订阅on(‘data‘), on(‘end‘)事件。涉及Buffer.concat()方法。

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

// 相当于创建可读流实例:new ReadStream
const rs = fs.createReadStream(path.resolve(__dirname,‘./1.txt‘), {
  flags: ‘r‘,
  highWaterMark: 2, //每次最多读取的字节数;默认64k
  start: 0,
  end: 10, //[start, end]设置读取范围
  autoClose: true, //读取完成后关闭文件
  encoding: true
});

// 内部监听data订阅,如果监听到,内部触发rs.emit(‘data‘);然后on的回调函数才执行。是异步操作。
let arr = [];// 存储二进制代码段
rs.on(‘data‘, function(chunk) {
  console.log(chunk)
  arr.push(chunk);
  rs.pause(); // 暂停读取
});
// 每2秒读取一次
let timer = setInterval(() => {
  rs.resume();
},2000)
// 监听完成事件
rs.on(‘end‘, function() {
  timer = null;
  clearInterval(timer);
  console.log(Buffer.concat(arr).toString());
})

2. 可写流

可写流可以控制每次写入的大小。主要有write(),end()方法。

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

let ws = fs.createWriteStream(path.resolve(__dirname, ‘./2.txt‘), {
  flags: ‘w‘, // 如果文件不存在,则创建;如果已经有内容,则先清空。
  encoding: ‘utf8‘,
  highWaterMark: 3, // 预计每次写入的字节数;默认16k
  start: 0, // 起始写入的位置
  autoClose: true // 写完后关闭文件
})

// write只能写入字符串或者buffer
let flag = ws.write(‘abcdef‘, function(err) {
  console.log(‘写入成功‘);
});
console.log(flag); //写入的长度大于highWaterMark
ws.end(‘结束‘);
// end方法之后不能再调用ewrite方法

4 . 文件拷贝 = 可读流+可写流

通过流实现文件拷贝。主要pipe方法。避免全部读取到内存后再写入的情况。

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

let rs = fs.createReadStream(path.resolve(__dirname, ‘./1.txt‘), {
  highWaterMark: 3
});
let ws = fs.createWriteStream(path.resolve(__dirname, ‘./2.txt‘), {
  highWaterMark: 2
});

rs.pipe(ws);
// 模拟实现pipe方法
function pipe(r,w) {
  rs.on(‘data‘, function(chunk) {
    let flag = ws.write(chunk);
    if (!flag) rs.pause();
  });
  // 单次写入完成
  ws.on(‘drain‘, function(){
    rs.resume();
    console.log("抽空");
  })
  rs.on(‘end‘, function(err) {
    console.log(‘文件读取完毕‘);
    ws.end();
  })
}
// pipe(rs,ws);

原文地址:https://www.cnblogs.com/lyraLee/p/12178437.html

时间: 2024-10-17 00:52:30

nodeJS文件流和事件的相关文章

nodejs用流来对文件操作

nodejs用流来对文件操作 by 伍雪颖 var fs = require('fs'); var reader = fs.createReadStream('in.txt'); var writer = fs.createWriteStream('out.txt'); reader.pipe(writer);

Nodejs读写流

Nodejs读写流 流的传输过程默认是以buffer的形式传输的,除非你给他设置其他编码形式,例如下面代码第二部分中,我们设置了流以utf8的编码形式进行传输: 1 var readable stream1 = ... 2 readable stream1.on('data', function(data) { 3 // data is a buffer; 4 console.log('got this data:', data); 5 }); 6 var readable stream2 =

C#做一个写txt文件流的测试,为什么配置低的机器写入的还快

测试机:笔记本i7 8G 固态硬盘 由于采取读码写入txt方式, 读码频率挺高,文件名为日期格式,当前采用每次读码打开文件写入的方式, 为什么没用sb,因为怕断电情况的数据丢失.所以采取每条存入的方式. 今天想对代码进行优化,采取文件流一直打开,不用每次打开关闭的情况,对效率进行测试. 1:新建项目 writetxt 2:添加时钟事件,定时写txt. 3:加两个写入方式 4:分别计时.查看效率. static object obj = new object(); public static vo

js学习笔记:事件——事件流、事件处理程序、事件对象

Javascript与HTML之间的交互是通过事件实现的. 事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间. 可以使用侦听器来预定事件,以便事件发生时执行相应代码. 事件流 事件流描述的是从页面中接受事件的顺序. 事件冒泡 IE的事件流叫做事件冒泡,即事件开始是由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档). 如果点击了页面中的一个div元素,那么这个click事件可能会按照如下顺序传播: < div> < body> < html> docume

Windows Form -----内容(12)流与事件

文件及文件夹操作:一.流:文件流:FileStream.用来操作文件.命名空间:System.IO;使用流的步骤:——最原生的流的操作.——通用性最强的.1.创建流.FileStream fs = new FileStream("文件路径",FileMode枚举);    FileMode.Appen - 如果存在,就打开追加:如果不存就新建    FileMode.Create - 如果存在,覆盖.如果不存在就新建.    FileMode.OpenOrCreate.如果存在就打开,

阿里云附件文件流的形式上传、下载

1.View附件上传 @using (Html.BeginForm("StartUpLoad", "ReferenceDocument", new {id = ViewBag.Id}, FormMethod.Post, new {enctype = "multipart/form-data"})) { <input type="file" name="filedata" id="fileUp

Node.js——fs模块(文件系统),创建、删除目录(文件),读取写入文件流

1 /* 2 1. fs.stat 检测是文件还是目录(目录 文件是否存在) 3 2. fs.mkdir 创建目录 (创建之前先判断是否存在) 4 3. fs.writeFile 写入文件(文件不存在就创建,但不能创建目录) 5 4. fs.appendFile 写入追加文件 6 5. fs.readFile 读取文件 7 6. fs.readdir 读取目录 8 7. fs.rename 重命名 9 8. fs.rmdir 删除目录 10 9. fs.unlink 删除文件 11 */ 12

C++文件流

文件流:以文件为输入输出对象的流 #include<fstream> 一.文件操作打开一个输入或输出文件 1.打开一个输出文件 ofstream fout; fout.open("1.txt"); 2.打开一个输入文件 ifstream  fin; fin.open("2.txt"); 3.打开一个文件,既可以输入也可以输出 fstream finout: finout.open("3.txt"): 更便捷方式   ofstream

文件流:&quot;fopen&quot;,&quot;fclose&quot;,“ftell”&quot;fseek&quot;,&quot;fgets&quot;,&quot;fprintf&quot; ,“feof”,&quot;fwrite&quot;,&quot;fread&quot;

char const* filename="D:/hello.txt"; "fopen", FILE *fp=fopen(char const *name,char const mode); e.g:FILE *fp = fopen(filename,"wb"); 打开文件流,name为要打开文件的路径,如这里的filename:mode 为对文件的操作模式,通常使用:"wb"(写操作),"rb"(读操作)