fs: add autoClose option to fs.createWriteStream
Add support to fs.createWriteStream and fs.createWriteStream for an autoClose option that behaves similarly to the autoClose option supported by fs.createReadStream and fs.ReadStream. When an instance of fs.createWriteStream created with autoClose === false finishes, it is not destroyed. Its underlying fd is not closed and it is the responsibility of the user to close it. PR-URL: https://github.com/nodejs/node/pull/3679 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
5a53cba784
commit
6039a7c1b5
@ -334,13 +334,20 @@ Returns a new [`WriteStream`][] object. (See [Writable Stream][]).
|
||||
{ flags: 'w',
|
||||
defaultEncoding: 'utf8',
|
||||
fd: null,
|
||||
mode: 0o666 }
|
||||
mode: 0o666,
|
||||
autoClose: true }
|
||||
|
||||
`options` may also include a `start` option to allow writing data at
|
||||
some position past the beginning of the file. Modifying a file rather
|
||||
than replacing it may require a `flags` mode of `r+` rather than the
|
||||
default mode `w`. The `defaultEncoding` can be any one of those accepted by [`Buffer`][].
|
||||
|
||||
If `autoClose` is set to true (default behavior) on `error` or `end`
|
||||
the file descriptor will be closed automatically. 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.
|
||||
|
||||
Like [`ReadStream`][], if `fd` is specified, `WriteStream` will ignore the
|
||||
`path` argument and will use the specified file descriptor. This means that no
|
||||
`'open'` event will be emitted. Note that `fd` should be blocking; non-blocking
|
||||
|
15
lib/fs.js
15
lib/fs.js
@ -1900,6 +1900,7 @@ function WriteStream(path, options) {
|
||||
this.mode = options.mode === undefined ? 0o666 : options.mode;
|
||||
|
||||
this.start = options.start;
|
||||
this.autoClose = options.autoClose === undefined ? true : !!options.autoClose;
|
||||
this.pos = undefined;
|
||||
this.bytesWritten = 0;
|
||||
|
||||
@ -1921,7 +1922,11 @@ function WriteStream(path, options) {
|
||||
this.open();
|
||||
|
||||
// dispose on finish.
|
||||
this.once('finish', this.close);
|
||||
this.once('finish', function() {
|
||||
if (this.autoClose) {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fs.FileWriteStream = fs.WriteStream; // support the legacy name
|
||||
@ -1930,7 +1935,9 @@ fs.FileWriteStream = fs.WriteStream; // support the legacy name
|
||||
WriteStream.prototype.open = function() {
|
||||
fs.open(this.path, this.flags, this.mode, function(er, fd) {
|
||||
if (er) {
|
||||
this.destroy();
|
||||
if (this.autoClose) {
|
||||
this.destroy();
|
||||
}
|
||||
this.emit('error', er);
|
||||
return;
|
||||
}
|
||||
@ -1953,7 +1960,9 @@ WriteStream.prototype._write = function(data, encoding, cb) {
|
||||
var self = this;
|
||||
fs.write(this.fd, data, 0, data.length, this.pos, function(er, bytes) {
|
||||
if (er) {
|
||||
self.destroy();
|
||||
if (self.autoClose) {
|
||||
self.destroy();
|
||||
}
|
||||
return cb(er);
|
||||
}
|
||||
self.bytesWritten += bytes;
|
||||
|
52
test/parallel/test-fs-write-stream-autoclose-option.js
Normal file
52
test/parallel/test-fs-write-stream-autoclose-option.js
Normal file
@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const file = path.join(common.tmpDir, 'write-autoclose-opt1.txt');
|
||||
common.refreshTmpDir();
|
||||
let stream = fs.createWriteStream(file, {flags: 'w+', autoClose: false});
|
||||
stream.write('Test1');
|
||||
stream.end();
|
||||
stream.on('finish', common.mustCall(function() {
|
||||
process.nextTick(common.mustCall(function() {
|
||||
assert.strictEqual(stream.closed, undefined);
|
||||
assert(stream.fd !== null);
|
||||
next();
|
||||
}));
|
||||
}));
|
||||
|
||||
function next() {
|
||||
// This will tell us if the fd is usable again or not
|
||||
stream = fs.createWriteStream(null, {fd: stream.fd, start: 0});
|
||||
stream.write('Test2');
|
||||
stream.end();
|
||||
stream.on('finish', common.mustCall(function() {
|
||||
assert.strictEqual(stream.closed, true);
|
||||
assert.strictEqual(stream.fd, null);
|
||||
process.nextTick(common.mustCall(next2));
|
||||
}));
|
||||
}
|
||||
|
||||
function next2() {
|
||||
// This will test if after reusing the fd data is written properly
|
||||
fs.readFile(file, function(err, data) {
|
||||
assert(!err);
|
||||
assert.strictEqual(data.toString(), 'Test2');
|
||||
process.nextTick(common.mustCall(next3));
|
||||
});
|
||||
}
|
||||
|
||||
function next3() {
|
||||
// This is to test success scenario where autoClose is true
|
||||
const stream = fs.createWriteStream(file, {autoClose: true});
|
||||
stream.write('Test3');
|
||||
stream.end();
|
||||
stream.on('finish', common.mustCall(function() {
|
||||
process.nextTick(common.mustCall(function() {
|
||||
assert.strictEqual(stream.closed, true);
|
||||
assert.strictEqual(stream.fd, null);
|
||||
}));
|
||||
}));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user