Don't use stat in fs.readFile[Sync]
authorisaacs <i@izs.me>
Thu, 23 Sep 2010 00:58:08 +0000 (17:58 -0700)
committerRyan Dahl <ry@tinyclouds.org>
Thu, 23 Sep 2010 05:06:32 +0000 (22:06 -0700)
Original patch c/o Evan Larkin <evan.larkin.iit@gmail.com>

lib/fs.js
test/simple/test-fs-read-file-sync-hostname.js [new file with mode: 0644]

index 705d223..24259c0 100644 (file)
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -43,71 +43,83 @@ fs.Stats.prototype.isSocket = function () {
   return this._checkModeProperty(constants.S_IFSOCK);
 };
 
-fs.readFile = function (path, encoding_, callback) {
-  var encoding = typeof(encoding_) == 'string' ? encoding_ : null;
-  var callback_ = arguments[arguments.length - 1];
-  var callback = (typeof(callback_) == 'function' ? callback_ : noop);
-  binding.stat(path, function (err, stat) {
-    if (err) { callback(err); return; }
-    binding.open(path, constants.O_RDONLY, 0666, function (err, fd) {
-      if (err) { callback(err); return; }
-      var size = stat.size;
-      var buffer = new Buffer(size);
-      var offset = 0;
-      function doRead() {
-        if (size < 1) {
-          binding.close(fd);
-          callback(null, encoding ? '' : buffer);
-          return;
-        }
-        // position is offset or null so we can read files on unseekable mediums
-        binding.read(fd, buffer, offset, size - offset, offset || null, function (err, amount) {
-          if (err) {
-            callback(err);
-            binding.close(fd);
-            return;
-          }
-          if (amount + offset < size) {
-            offset += amount;
-            doRead();
-            return;
-          }
-          binding.close(fd);
-          if (encoding) {
-            try {
-              var str = buffer.toString(encoding);
-            } catch (err) {
-              callback(err);
-              return;
-            }
-            callback(null, str);
-          } else {
-            callback(null, buffer);
-          }
+fs.readFile = function (path, encoding_) {
+  var encoding = typeof(encoding_) === 'string' ? encoding_ : null;
+  var callback = arguments[arguments.length-1];
+  if (typeof(callback) !== 'function') callback = noop;
+  var readStream = fs.createReadStream(path);
+  var buffers = [];
+  var nread = 0;
+  readStream.on("data", function (chunk) {
+    buffers.push(chunk);
+    nread += chunk.length;
+  });
+  readStream.on("error", function (er) {
+    callback(er);
+    readStream.destroy();
+  });
+  readStream.on("end", function () {
+    // copy all the buffers into one
+    var buffer;
+    switch (buffers.length) {
+      case 0: buffer = new Buffer(0); break;
+      case 1: buffer = buffers[0]; break;
+      default: // concat together
+        buffer = new Buffer(nread);
+        var n = 0;
+        buffers.forEach(function (b) {
+          var l = b.length;
+          b.copy(buffer, n, 0, l);
+          n += l;
         });
+        break;
+    }
+    if (encoding) {
+      try {
+        buffer = buffer.toString(encoding);
+      } catch (er) {
+        return callback(er);
       }
-      doRead();
-    });
+    }
+    callback(null, buffer);
   });
 };
 
 fs.readFileSync = function (path, encoding) {
   var fd = fs.openSync(path, constants.O_RDONLY, 0666);
-  var stat = fs.statSync(path);
-  var buffer = new Buffer(stat.size);
+  var buffer = new Buffer(4048);
+  var buffers = [];
   var nread = 0;
+  var lastRead = 0;
 
-  while (nread < buffer.length) {
-    nread += fs.readSync(fd, buffer, nread, buffer.length - nread, null);
-  }
+  do {
+    if (lastRead) {
+      buffer._bytesRead = lastRead;
+      nread += lastRead;
+      buffers.push(buffer);
+    }
+    var buffer = new Buffer(4048);
+    lastRead = fs.readSync(fd, buffer, 0, buffer.length, null);
+  } while (lastRead > 0);
 
   fs.closeSync(fd);
 
-  if (encoding) {
-    return buffer.toString(encoding);
+  if (buffers.length > 1) {
+    var offset = 0;
+    var i;
+    buffer = new Buffer(nread);
+    buffers.forEach(function (i) {
+      if (!i._bytesRead) return;
+      i.copy(buffer,offset,0,i._bytesRead);
+      offset += i._bytesRead;
+    })
   } else {
-    return buffer;
+    //buffers has exactly 1 (possibly zero length) buffer, so this should be a shortcut
+    buffer = buffers[0].slice(0, buffers[0]._bytesRead);
   }
+
+  if (encoding) buffer = buffer.toString(encoding);
+  return buffer;
 };
 
 
diff --git a/test/simple/test-fs-read-file-sync-hostname.js b/test/simple/test-fs-read-file-sync-hostname.js
new file mode 100644 (file)
index 0000000..1929ac8
--- /dev/null
@@ -0,0 +1,9 @@
+common = require("../common");
+assert = common.assert
+var fs = require('fs');
+
+// test reading from hostname
+if (process.platform === "linux2") {
+  var hostname = fs.readFileSync('/proc/sys/kernel/hostname');
+  assert.ok(hostname.length > 0);
+}