Browse Source

Faster fs.readFile and fs.readFileSync

v0.9.1-release
isaacs 13 years ago
parent
commit
1a2255ab44
  1. 125
      lib/fs.js
  2. 4
      test/simple/test-fs-sync-fd-leak.js

125
lib/fs.js

@ -103,93 +103,88 @@ fs.readFile = function(path, encoding_) {
var encoding = typeof(encoding_) === 'string' ? encoding_ : null; var encoding = typeof(encoding_) === 'string' ? encoding_ : null;
var callback = arguments[arguments.length - 1]; var callback = arguments[arguments.length - 1];
if (typeof(callback) !== 'function') callback = noop; 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) { // first, stat the file, so we know the size.
error = er; var size;
readStream.destroy(); var buffer;
if (!readStream.fd) { var pos = 0;
readStream.emit('close'); var fd;
}
}); fs.open(path, constants.O_RDONLY, 438 /*=0666*/, function(er, fd_) {
if (er) return callback(er);
fd = fd_;
readStream.on('close', function() { fs.fstat(fd, function(er, st) {
if (error) { if (er) return callback(er);
return callback(error); size = st.size;
if (size === 0) {
buffer = new Buffer(0);
return afterRead(null, 0);
} }
// copy all the buffers into one buffer = new Buffer(size);
var buffer; read();
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; });
function read() {
fs.read(fd, buffer, pos, size - pos, pos, afterRead);
} }
if (encoding) {
try { function afterRead(er, bytesRead) {
buffer = buffer.toString(encoding); if (er) {
} catch (er) { return fs.close(fd, function(er2) {
return callback(er); return callback(er);
});
} }
pos += bytesRead;
if (pos === size) close();
else read();
} }
callback(null, buffer);
function close() {
fs.close(fd, function(er) {
if (encoding) buffer = buffer.toString(encoding);
return callback(er, buffer);
}); });
}
}; };
fs.readFileSync = function(path, encoding) { fs.readFileSync = function(path, encoding) {
var fd = fs.openSync(path, constants.O_RDONLY, 438 /*=0666*/); 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 { try {
do { size = fs.fstatSync(fd).size;
if (lastRead) { threw = false;
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);
} finally { } finally {
if (threw) fs.closeSync(fd);
}
if (size === 0) {
fs.closeSync(fd); fs.closeSync(fd);
return encoding ? '' : new Buffer(0);
} }
if (buffers.length > 1) { var buffer = new Buffer(size);
var offset = 0; var pos = 0;
var i;
buffer = new Buffer(nread); while (pos < size) {
buffers.forEach(function(i) { var threw = true;
if (!i._bytesRead) return; try {
i.copy(buffer, offset, 0, i._bytesRead); var bytesRead = fs.readSync(fd, buffer, pos, size - pos, pos);
offset += i._bytesRead; threw = false;
}); } finally {
} else if (buffers.length) { if (threw) fs.closeSync(fd);
// 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);
} }
pos += bytesRead;
}
fs.closeSync(fd);
if (encoding) buffer = buffer.toString(encoding); if (encoding) buffer = buffer.toString(encoding);
return buffer; return buffer;
}; };

4
test/simple/test-fs-sync-fd-leak.js

@ -38,6 +38,10 @@ fs.writeSync = function() {
throw new Error('BAM'); throw new Error('BAM');
}; };
fs.fstatSync = function() {
throw new Error('BAM');
};
ensureThrows(function() { ensureThrows(function() {
fs.readFileSync('dummy'); fs.readFileSync('dummy');
}); });

Loading…
Cancel
Save