Skip to content

Commit 61785af

Browse files
committed
Initial write stream implementation
1 parent 6670154 commit 61785af

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

lib/fs.js

+87
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,90 @@ exports.realpath = function(path, callback) {
375375
callback(null, normalize(path));
376376
});
377377
}
378+
379+
exports.fileWriteStream = function(path, options) {
380+
return new FileWriteStream(path, options);
381+
};
382+
383+
var FileWriteStream = exports.FileWriteStream = function(path, options) {
384+
this.path = path;
385+
this.fd = null;
386+
this.closed = false;
387+
388+
this.flags = 'w';
389+
this.encoding = 'binary';
390+
this.mode = 0666;
391+
392+
process.mixin(this, options || {});
393+
394+
var
395+
self = this,
396+
queue = [],
397+
busy = false;
398+
399+
queue.push([fs.open, this.path, this.flags, this.mode]);
400+
401+
function pump() {
402+
if (busy) {
403+
return;
404+
}
405+
406+
var args = queue.shift();
407+
if (!args) {
408+
return self.emit('drain');
409+
}
410+
411+
busy = true;
412+
413+
var method = args.shift();
414+
415+
args.push(function(err) {
416+
busy = false;
417+
418+
if (err) {
419+
self.emit('error', err);
420+
return;
421+
}
422+
423+
// save reference for file pointer
424+
if (method === fs.open) {
425+
self.fd = arguments[1];
426+
self.emit('open', self.fd);
427+
}
428+
429+
// stop pumping after close
430+
if (method === fs.close) {
431+
self.emit('close');
432+
return;
433+
}
434+
435+
pump();
436+
});
437+
438+
// Inject the file pointer
439+
if (method !== fs.open) {
440+
args.unshift(self.fd);
441+
}
442+
443+
method.apply(null, args);
444+
};
445+
446+
this.write = function(data) {
447+
if (this.closed) {
448+
throw new Error('stream already closed');
449+
}
450+
451+
queue.push([fs.write, data, undefined, this.encoding]);
452+
pump();
453+
return false;
454+
};
455+
456+
this.close = function() {
457+
this.closed = true;
458+
queue.push([fs.close,]);
459+
pump();
460+
};
461+
462+
pump();
463+
};
464+
FileWriteStream.prototype.__proto__ = process.EventEmitter.prototype;

test/simple/test-file-write-stream.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
process.mixin(require('../common'));
2+
3+
var
4+
fn = path.join(fixturesDir, "write.txt"),
5+
file = fs.fileWriteStream(fn),
6+
7+
EXPECTED = '0123456789',
8+
9+
callbacks = {
10+
open: -1,
11+
drain: -2,
12+
close: -1
13+
};
14+
15+
file
16+
.addListener('open', function(fd) {
17+
callbacks.open++;
18+
assert.equal('number', typeof fd);
19+
})
20+
.addListener('drain', function() {
21+
callbacks.drain++;
22+
if (callbacks.drain == -1) {
23+
assert.equal(EXPECTED, fs.readFileSync(fn));
24+
file.write(EXPECTED);
25+
} else if (callbacks.drain == 0) {
26+
assert.equal(EXPECTED+EXPECTED, fs.readFileSync(fn));
27+
file.close();
28+
}
29+
})
30+
.addListener('close', function() {
31+
callbacks.close++;
32+
assert.throws(function() {
33+
file.write('should not work anymore');
34+
});
35+
36+
fs.unlinkSync(fn);
37+
});
38+
39+
for (var i = 0; i < 10; i++) {
40+
assert.strictEqual(false, file.write(i));
41+
}
42+
43+
process.addListener('exit', function() {
44+
for (var k in callbacks) {
45+
assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
46+
}
47+
});

0 commit comments

Comments
 (0)