0

I'm trying implement a stream which returns one symbol from file on each 'data' event. I finished with code bellow:

var util = require('util'),
    fs = require('fs'),
    Readable = require('stream').Readable;

var util = require('util');
var Readable = require('stream').Readable;

var SymbolReadStream = function(filename, options) {
  Readable.call(this);
  this._readable = fs.createReadStream(filename, options).pause();
  self = this;
  this._readable.on('readable', function() {
    var chunk;
    chunk = self._readable.read(1);
    // I believe the problem is here
    self._readable.pause();
  });
};

util.inherits(SymbolReadStream, Readable); // inherit the prototype methods

SymbolReadStream.prototype._read = function() {
  this._readable.resume();
};

var r = new SymbolReadStream("test.txt", {
  encoding: 'utf8',
});
r.on('data', function(el) {
  console.log(el);
});

but this code doesn't work. Please help. Is there an easier way to achieve the behavior?

kharandziuk
  • 12,020
  • 17
  • 63
  • 121

2 Answers2

4

This post give a great clue how to answer your question.

Also, you should take a loop at pipe that would be a cleaner way to accomplish what you're trying to do: piping an adapter to the filestream instead of wrapping it up

That said, personaly I wont reinvent the wheel here, and would just search for modules that can accomplish that. Especially "split" modules, making them split on every char, instead on new lines. As an example, event-stream has a split method that "takes the same arguments as string.split except it defaults to '\n' instead of ','". So the logic would be to try myStream.pipe(es.split('')) but the modules takes this like myStream.pipe(es.split()) which breaks on lines. So here's my solution, using a regex to say "break on each char"

var es = require('event-stream');
var fs = require('fs');

var symbolStream = fs.createReadStream(filename, options).pipe(es.split(/(?!$)/));

EDIT: event-stream seems to use split module internally, so you can even try

var split = require('split');
var fs = require('fs');

var symbolStream = fs.createReadStream(filename, options).pipe(split(/(?!$)/));

(this loose test is responsible of converting '' to \r\n)

Community
  • 1
  • 1
Cyril CHAPON
  • 3,556
  • 4
  • 22
  • 40
  • That's this one I took some time to document. Provided you some great doc, 3-liner performant code instead of a 40-liner wheel reinvention that you accepted as an answer. Not realy fair, since the other question is quite harder and time consuming. – Cyril CHAPON May 13 '15 at 15:48
1

In you stream implementation there is no emitting 'data' event to handler. Because of it, console.log are never called. After adding events, they will be streamed symbol by symbol. Example below:

var util = require('util'),
  fs = require('fs'),
  Readable = require('stream').Readable;

function SymbolReadStream(filename, options) {
  if (!(this instanceof SymbolReadStream)) {
    return new SymbolReadStream(length, options);
  }

  Readable.call(this);
  this._readable = fs.createReadStream(filename, options);
}

util.inherits(SymbolReadStream, Readable); // inherit the prototype methods

SymbolReadStream.prototype._read = function() {
  var self = this;
  this._readable.on('readable', function() {
    var chunk;
    while (null !== (chunk = self._readable.read(1))) {
      self.emit('data', chunk);
    }
  });
  this._readable.on('end', function() {
    self.emit('end');
  });
};

var r = new SymbolReadStream("test.txt", {
  encoding: 'utf8',
});
r.on('data', function(el) {
  console.log(el);
});
r.on('end', function(el) {
  console.log('done');
});
vanadium23
  • 3,516
  • 15
  • 27