Question

In a previous question it seemed that the only way to do random-access reads from a file in node.js is to use fs.createReadStream() with its optional fd, start, and end fields.

This worked fine in my simplest tests. But in my project I need to repeatedly read from different offsets of a binary file. This failed in a strange way so I came up with a minimal test case:

var fs = require('fs');

fs.open('test.txt', 'r', function (err, fd) {
  if (err) {
    console.error('error opening file: ' + err);
  } else {
    fs.createReadStream(null, {fd: fd, start: 2, end: 5}).on('error', function (err) {
        throw e;
      }).on('close', function () {
        console.log('outer close');
      }).on('data', function (data) {
        console.log('outer data', data);
      }).on('end', function () {
        console.log('outer end');

        fs.createReadStream(null, {fd: fd, start: 0, end: 3}).on('error', function (err) {
            throw e;
          }).on('close', function () {
            console.log('inner close');
          }).on('data', function (data) {
            console.log('inner data', data);
          }).on('end', function () {
            console.log('inner end');

            // more code to execute after both reads
          });
      });
  }
});

The inner end event is never received. (The outer close is received inconsistently, but I don't need to attach code to it.)

I've implemented this project before in Perl and even in JavaScript as a Firefox extension, but it's proving difficult under node. This is also a test for whether I can start using node.js as a general purpose scripting language.

Was it helpful?

Solution

The issue is that the outer ReadStream will close the fd after it is used, so reusing it on the second ReadStream will fail. The newest Node unstable actually has an autoClose options for ReadStreams but that is not part of stable yet.

The real answer that is that the information given to you in your previous question is incorrect. createReadStream is implemented using all public APIs, so there is nothing that it can do that you can't do too. In this case, you can just use fs.read with its position argument.

var fs = require('fs');                                                         

fs.open('test.txt', 'r', function (err, fd) {                                   
  if (err) {                                                                    
    console.error('error opening file: ' + err);                                
  } else {                                                                      
    fs.read(fd, new Buffer(4), 0, 4, 2, function(err, bytesRead, data){        
      if (err) throw err;                                                       
      console.log('outer data', data);                                          

      fs.read(fd, new Buffer(3), 0, 3, 0, function(err, bytesRead, data2){   
        if (err) throw err;                                                     
        console.log('inner data', data2);                                       
        fs.close(fd);                                                           

        // more code to execute after both reads                                
      });                                                                       
    });                                                                         
  }                                                                             
});   
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top