From dcaebec2086a330b50f1494350021c3e0e64efa0 Mon Sep 17 00:00:00 2001 From: Farid Neshat Date: Mon, 17 Dec 2012 23:03:19 +0800 Subject: [PATCH] fs: add autoClose=true option to fs.createReadStream --- doc/api/fs.markdown | 9 ++++++- lib/fs.js | 13 +++++++--- test/simple/test-fs-read-stream.js | 38 ++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 2bc8461c7a..100bcc19d8 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -634,13 +634,20 @@ Returns a new ReadStream object (See `Readable Stream`). encoding: null, fd: null, mode: 0666, - bufferSize: 64 * 1024 + bufferSize: 64 * 1024, + autoClose: true } `options` can include `start` and `end` values to read a range of bytes from the file instead of the entire file. Both `start` and `end` are inclusive and start at 0. The `encoding` can be `'utf8'`, `'ascii'`, or `'base64'`. +If `autoClose` is false, then the file descriptor won't be closed, even if +there's an error. It is your responsiblity to close it and make sure +there's no file descriptor leak. If `autoClose` is set to true (default +behavior), on `error` or `end` the file descriptor will be closed +automatically. + An example to read the last 10 bytes of a file which is 100 bytes long: fs.createReadStream('sample.txt', {start: 90, end: 99}); diff --git a/lib/fs.js b/lib/fs.js index 96af63186c..44c3fc2e77 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1412,6 +1412,7 @@ function ReadStream(path, options) { this.start = options.hasOwnProperty('start') ? options.start : undefined; this.end = options.hasOwnProperty('start') ? options.end : undefined; + this.autoClose = options.hasOwnProperty('autoClose') ? options.autoClose : true; this.pos = undefined; if (this.start !== undefined) { @@ -1435,7 +1436,9 @@ function ReadStream(path, options) { this.open(); this.on('end', function() { - this.destroy(); + if (this.autoClose) { + this.destroy(); + } }); } @@ -1445,7 +1448,9 @@ ReadStream.prototype.open = function() { var self = this; fs.open(this.path, this.flags, this.mode, function(er, fd) { if (er) { - self.destroy(); + if (this.autoClose) { + self.destroy(); + } self.emit('error', er); return; } @@ -1499,7 +1504,9 @@ ReadStream.prototype._read = function(n, cb) { function onread(er, bytesRead) { if (er) { - self.destroy(); + if (self.autoClose) { + self.destroy(); + } return cb(er); } diff --git a/test/simple/test-fs-read-stream.js b/test/simple/test-fs-read-stream.js index a88802b654..9452f95c6d 100644 --- a/test/simple/test-fs-read-stream.js +++ b/test/simple/test-fs-read-stream.js @@ -151,3 +151,41 @@ stream.on('end', function() { var pauseRes = fs.createReadStream(rangeFile); pauseRes.pause(); pauseRes.resume(); + +var file7 = fs.createReadStream(rangeFile, {autoClose: false }); +file7.on('data', function() {}); +file7.on('end', function() { + process.nextTick(function() { + assert(!file7.closed); + assert(!file7.destroyed); + file7Next(); + }); +}); + +function file7Next(){ + // This will tell us if the fd is usable again or not. + file7 = fs.createReadStream(null, {fd: file7.fd, start: 0 }); + file7.data = ''; + file7.on('data', function(data) { + file7.data += data; + }); + file7.on('end', function(err) { + assert.equal(file7.data, 'xyz\n'); + process.nextTick(function() { + assert(file7.closed); + assert(file7.destroyed); + }); + }); +} + +// Just to make sure autoClose won't close the stream because of error. +var file8 = fs.createReadStream(null, {fd: 13337, autoClose: false }); +file8.on('data', function() {}); +file8.on('error', common.mustCall(function() {})); +file8.on('end', function() { + process.nextTick(function() { + assert(!file8.closed); + assert(!file8.destroyed); + assert(file8.fd); + }); +});