同时使用fs.createReadStream()和EISDIR同时打开和错误
在实现简单的静态服务中间件时,我偶然发现了下面的代码:
fs = require('fs'); util = require('util'); stream = fs.createReadStream('/'); stream.on('open', function(fd) { console.log('opened! ' + util.inspect(fd)); }); stream.on('error', function(err) { console.log('error! ' + util.inspect(err)); });
当参数是目录时, open
和error
事件都会被发出!
$ node test.js opened! 11 error! { [Error: EISDIR, read] errno: 28, code: 'EISDIR' }
我以为我有open
或error
,从来没有在同一时间。
什么是优雅的方式来区分好的open
和坏的open
而不诉诸明确testingfd
与stat
是目录? 还有其他类似的情况吗?
当您在Node中创build可读stream时,代码将尝试打开文件并读取内容(如果未提供fd
)。 你可以通过代码看到:
调用createReadStream()
创build一个ReadStream
对象,如果fd
不是数字( 链接到源 ),将调用this.open()
):
if (!util.isNumber(this.fd)) this.open();
这调用fs.open
,我猜猜目录上打开目录? (这有点奇怪,为什么允许这样做没有错误,但代码最终击中本地绑定层,并继续。)打开它,代码发出“打开”事件,并开始读取的内容该文件( 链接到源 ):
ReadStream.prototype.open = function() { var self = this; fs.open(this.path, this.flags, this.mode, function(er, fd) { if (er) { if (self.autoClose) { self.destroy(); } self.emit('error', er); return; } self.fd = fd; self.emit('open', fd); // start the flow of data. self.read(); }); };
这是在调用fs.read
的过程中,导致错误,这是发送到ReadStream
的callbackonRead
( 链接到源 ):
function onread(er, bytesRead) { if (er) { if (self.autoClose) { self.destroy(); } self.emit('error', er);
因此,因为createReadStream
调用立即打开并开始读取文件的内容(如果文件描述符未被传递),事件将按照您所看到的发送。 首先open
事件,然后试图读取文件,失败,并发出error
事件。
由于这是一个可读的stream ,因此您可能需要考虑监听data
事件,而不是open
事件来判断这是否是可接受的文件,因为您正在立即读取。 类似的东西:
fs = require('fs'); util = require('util'); stream = fs.createReadStream('/'); stream.on('data', function(chunk) { console.log('data! ' + chunk.toString()); }); stream.on('error', function(err) { console.log('error! ' + util.inspect(err)); });
在testing中,你会在文件上点击data
,并在目录上error
。
我已经结束了以下方法:
-
fs.open(path, 'r', function(err, fd) { ... })
获取文件描述符fd
; -
fs.fstat(fd, function(err, stats) { ... })
给定给定的文件描述符; -
stats.isDirectory()
来处理EISDIR
情况; -
stream = fs.createReadStream(null, { fd: fd, flags: 'r' })
最终获得可读的文件stream;
通过这种方式,我可以保护自己免受与目录之间的交换文件的影响,反之亦然,因为即使有人做了欺骗,其文件描述符仍然有效。