var fs = require('fs');
var file = fs.createReadStream('./zeros.txt');
var dataSize = 0;
file.on('readable', function () {
var data = file.read(10);
console.log('readable size = ', data.length);
console.log(data.toString());
});
thie文件" zeros.txt"包含700个字符" 0"
据我了解,在拨打(10)呼叫后,流必须停止并等待新的读取()调用。但是,呼叫的结果:
readable size = 10
0000000000
readable size = 10
0000000000
node.js之后,将加载文件(整个或仅仅是一个部分,取决于文件本身的大小),然后将其发射readable event
(使用push()方法)指出某些数据已被读取到缓冲区中并准备使用。然后,在调用read(10)
后,您将释放缓冲区,然后Node.js将自动填充缓冲区,然后再次发射readable event
,以指示仍然有一些数据可以从缓冲区中读取。如果您致电read(700)
,则不会再次发出下一个readable event
。
流动和非流量模式
与聆听data event
时,流将保持在所谓的非流动模式。这意味着开发人员将负责释放流(从流中读取)。另一方面,在收听data event
时,流将自动进入所谓的流动模式,这意味着流本身将负责释放自身,即,流将填充和空本身直到他的基础系统(在这种情况下,zero.txt
将被充分阅读)。注意缓冲区将在两种模式下自动填充数据。
流动模式
非流动模式的一个示例,我们必须手动清空缓冲区(使用read()
方法):
var fs = require('fs'),
util = require('util');
// I have increased the file size to 19 MB (about 19 mln characters);
// Cause of the buffer capicity.
var file = fs.createReadStream('./zeros.txt');
var dataSize = 0;
// Readable will be called when the buffer has been filled with data.
// Initially Node.js will fill the buffer with data automatically,
// so this event will be called automatically aswell of course.
// Once the buffer will be free again after the first fill, Node.js
// will fill the buffer automatically again. Node.js just watches this stream
// and makes sure to fill it, when there is still some unread data in the zero.txt file.
file.on('readable', function() {
var i = 0; // we will count how many times did while loop, for fun
// If the buffer will be empty Node will write data to the buffer
// automatically, we don't have to care about that. However
// you can specify the buffer capicty manually if you want.
console.log('loading more data from the underlying system');
// This will make the stream read 1000 bytes
// it will also return a value NULL if there is not enough
// data to read from the buffer (meaning buffer has been fully read
// or there is still some data but you are trying to read 1000 bytes
// and there is less than 1000 bytes left)
while(file.read(1000) !== null) {
i++;
}
// At this moment while loop has read everything from the buffer.
// The buffer is now empty. After this comment console.log will execute
// Node.js will fill the buffer again with new data automatically.
// And then the 'readable' event will fire again.
console.log("had to loop: " + i + " times before the buffer was empty");
})
控制台的最后几个结果:
loading more data from the underlying system
had to loop: 66 times before the buffer was empty
loading more data from the underlying system
had to loop: 65 times before the buffer was empty
loading more data from the underlying system
had to loop: 66 times before the buffer was empty
loading more data from the underlying system
had to loop: 46 times before the buffer was empty
loading more data from the underlying system
had to loop: 1 times before the buffer was empty
非流动模式
那是非流动模式,因为我们必须手动释放缓冲区。现在,我们将继续进行流动模式。在Readable Stream
上设置data event listener
将流从初始non-flowing mode
切换为flowing mode
。这意味着缓冲区将自动清空。Node.js将您的数据作为data event listener
中的参数传递给您,一旦该功能执行缓冲区将再次清空,如果仍然存在一些数据,那么基础源缓冲区中仍会自动填充新数据,然后数据事件将会自动填写再次发出。注意:如果您正在收听data
事件,并且readable event
都会触发,但是data event listener
首先将空缓冲区空,然后readable event
将触发,以便您的read()
始终返回NULL
。
var fs = require('fs'),
util = require('util');
var file = fs.createReadStream('./zeros.txt');
var dataSize = 0;
file.on('data', function() {
// Once this listener will stop executing new data will be read
// into the buffer and then the 'data' event will be emitted
// again.
console.log('data has been loaded and emptied!')
})
file.on('readable', function () {
// Notice we want to try to read 1 byte from the buffer
// but in the console we see that the read() method
// resulted in NULL, which means that the buffer is empty.
// That's of course because we enterd the flowing mode
// by setting up the 'data' event. (In flowing mode)
// after the execution of the 'data' event all data
// from the buffer will be read, but the execution
// of listeners will continue. After all the event listeners
// attached to this stream will execute, Node.js will fill
// the buffer automatically again.
console.log('readable ' + file.read(1))
});
控制台的最后几个结果:
data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null
data has been loaded and emptied!
readable null
我的答案基于0.12.4的版本。
1:当当前内部缓冲区长度为0或小于 highWaterMark
属性的值时,从Stream.Readable
延伸的每个read(n)
函数都会触发内部_read(n)
函数。
2:仅当当前内部缓冲区长度为0或从内部缓冲区读取的数据为null或时,readable
事件才会触发。。
让我们以您的代码为例,看看发生了什么。
file.on('readable', function () {
readable
事件处理程序寄存器将触发read(0)
功能从文件加载到内部缓冲区。如果您不覆盖 highWaterMark
的值,它最多将加载64 * 1024 = 65535。在您的代码中,它从文件" zeros.txt"中加载了所有数据。之后,它将触发readable
事件,因为调用read(0)
函数之前的内部缓冲区长度为0。
var data = file.read(10);
在处理程序中,您再次调用read(10)
功能。这也将触发从文件到缓冲区的加载过程。但是,此时不会加载数据。因此,将推动 null
指示阅读过程已完成。第二个readable
事件已触发。这就是您应该看到的原因,只看到两个readable
事件。
如果您读取大小大于65535字节(几乎66kb)的文件,则只能查看一个readable
事件触发。
您不应该像这样编写readable
事件处理程序,您应该参考以下内容:
var chunk;
while( null !== ( chunk = fs.read() ) ) {
//handle the chunk
}
如果您想以自己的方式处理一些特殊的事情,请注意规则;否则,该程序将保持在"暂停"状态,将不再读取数据,并且将不再检索数据。
请参阅fs.ReadStream and stream.able。