Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Faster fs.readFile and fs.readFileSync

  • Loading branch information...
commit 1a2255ab44d4c81e6f62a69dca5710f4f31b8a00 1 parent ee6c118
@isaacs isaacs authored
Showing with 68 additions and 69 deletions.
  1. +64 −69 lib/fs.js
  2. +4 −0 test/simple/test-fs-sync-fd-leak.js
View
133 lib/fs.js
@@ -103,93 +103,88 @@ 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;
- var error;
-
- readStream.on('data', function(chunk) {
- buffers.push(chunk);
- nread += chunk.length;
- });
- readStream.on('error', function(er) {
- error = er;
- readStream.destroy();
- if (!readStream.fd) {
- readStream.emit('close');
- }
+ // first, stat the file, so we know the size.
+ var size;
+ var buffer;
+ var pos = 0;
+ var fd;
+
+ fs.open(path, constants.O_RDONLY, 438 /*=0666*/, function(er, fd_) {
+ if (er) return callback(er);
+ fd = fd_;
+
+ fs.fstat(fd, function(er, st) {
+ if (er) return callback(er);
+ size = st.size;
+ if (size === 0) {
+ buffer = new Buffer(0);
+ return afterRead(null, 0);
+ }
+
+ buffer = new Buffer(size);
+ read();
+ });
});
- readStream.on('close', function() {
- if (error) {
- return callback(error);
- }
+ function read() {
+ fs.read(fd, buffer, pos, size - pos, pos, afterRead);
+ }
- // 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) {
+ function afterRead(er, bytesRead) {
+ if (er) {
+ return fs.close(fd, function(er2) {
return callback(er);
- }
+ });
}
- callback(null, buffer);
- });
+
+ pos += bytesRead;
+ if (pos === size) close();
+ else read();
+ }
+
+ function close() {
+ fs.close(fd, function(er) {
+ if (encoding) buffer = buffer.toString(encoding);
+ return callback(er, buffer);
+ });
+ }
};
fs.readFileSync = function(path, encoding) {
var fd = fs.openSync(path, constants.O_RDONLY, 438 /*=0666*/);
- var buffer = new Buffer(4048);
- var buffers = [];
- var nread = 0;
- var lastRead = 0;
+ var size;
+ var threw = true;
try {
- 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);
+ size = fs.fstatSync(fd).size;
+ threw = false;
} finally {
+ if (threw) fs.closeSync(fd);
+ }
+
+ if (size === 0) {
fs.closeSync(fd);
+ return encoding ? '' : new Buffer(0);
}
- 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 if (buffers.length) {
- // buffers has exactly 1 (possibly zero length) buffer, so this should
- // be a shortcut
- buffer = buffers[0].slice(0, buffers[0]._bytesRead);
- } else {
- buffer = new Buffer(0);
+ var buffer = new Buffer(size);
+ var pos = 0;
+
+ while (pos < size) {
+ var threw = true;
+ try {
+ var bytesRead = fs.readSync(fd, buffer, pos, size - pos, pos);
+ threw = false;
+ } finally {
+ if (threw) fs.closeSync(fd);
+ }
+
+ pos += bytesRead;
}
+ fs.closeSync(fd);
+
if (encoding) buffer = buffer.toString(encoding);
return buffer;
};
View
4 test/simple/test-fs-sync-fd-leak.js
@@ -38,6 +38,10 @@ fs.writeSync = function() {
throw new Error('BAM');
};
+fs.fstatSync = function() {
+ throw new Error('BAM');
+};
+
ensureThrows(function() {
fs.readFileSync('dummy');
});
Please sign in to comment.
Something went wrong with that request. Please try again.