Browse Source

fs: Support mode/flag options to read/append/writeFile

Fix #4841
v0.9.11-release
isaacs 12 years ago
parent
commit
0928a526dd
  1. 44
      doc/api/fs.markdown
  2. 128
      lib/fs.js
  3. 11
      test/simple/test-fs-append-file-sync.js
  4. 9
      test/simple/test-fs-append-file.js
  5. 9
      test/simple/test-fs-write-file.js

44
doc/api/fs.markdown

@ -410,7 +410,12 @@ The callback is given the three arguments, `(err, bytesRead, buffer)`.
Synchronous version of `fs.read`. Returns the number of `bytesRead`. Synchronous version of `fs.read`. Returns the number of `bytesRead`.
## fs.readFile(filename, [encoding], [callback]) ## fs.readFile(filename, [options], [callback])
* `filename` {String}
* `options` {Object}
* `encoding` {String | Null} default = `null`
* `flag` {String} default = `'r'`
Asynchronously reads the entire contents of a file. Example: Asynchronously reads the entire contents of a file. Example:
@ -425,19 +430,28 @@ contents of the file.
If no encoding is specified, then the raw buffer is returned. If no encoding is specified, then the raw buffer is returned.
## fs.readFileSync(filename, [encoding]) ## fs.readFileSync(filename, [options])
Synchronous version of `fs.readFile`. Returns the contents of the `filename`. Synchronous version of `fs.readFile`. Returns the contents of the `filename`.
If `encoding` is specified then this function returns a string. Otherwise it If the `encoding` option is specified then this function returns a
returns a buffer. string. Otherwise it returns a buffer.
## fs.writeFile(filename, data, [options], [callback])
## fs.writeFile(filename, data, [encoding], [callback]) * `filename` {String}
* `data` {String | Buffer}
* `options` {Object}
* `encoding` {String | Null} default = `'utf8'`
* `mode` {Number} default = `438` (aka `0666` in Octal)
* `flag` {String} default = `'w'`
Asynchronously writes data to a file, replacing the file if it already exists. Asynchronously writes data to a file, replacing the file if it already exists.
`data` can be a string or a buffer. The `encoding` argument is ignored if `data` can be a string or a buffer.
`data` is a buffer. It defaults to `'utf8'`.
The `encoding` option is ignored if `data` is a buffer. It defaults
to `'utf8'`.
Example: Example:
@ -446,15 +460,21 @@ Example:
console.log('It\'s saved!'); console.log('It\'s saved!');
}); });
## fs.writeFileSync(filename, data, [encoding]) ## fs.writeFileSync(filename, data, [options])
The synchronous version of `fs.writeFile`. The synchronous version of `fs.writeFile`.
## fs.appendFile(filename, data, encoding='utf8', [callback]) ## fs.appendFile(filename, data, [options], [callback])
* `filename` {String}
* `data` {String | Buffer}
* `options` {Object}
* `encoding` {String | Null} default = `'utf8'`
* `mode` {Number} default = `438` (aka `0666` in Octal)
* `flag` {String} default = `'a'`
Asynchronously append data to a file, creating the file if it not yet exists. Asynchronously append data to a file, creating the file if it not yet exists.
`data` can be a string or a buffer. The `encoding` argument is ignored if `data` can be a string or a buffer.
`data` is a buffer.
Example: Example:
@ -463,7 +483,7 @@ Example:
console.log('The "data to append" was appended to file!'); console.log('The "data to append" was appended to file!');
}); });
## fs.appendFileSync(filename, data, encoding='utf8') ## fs.appendFileSync(filename, data, [options])
The synchronous version of `fs.appendFile`. The synchronous version of `fs.appendFile`.

128
lib/fs.js

@ -165,10 +165,20 @@ fs.existsSync = function(path) {
} }
}; };
fs.readFile = function(path, encoding_) { fs.readFile = function(path, options, callback_) {
var encoding = typeof(encoding_) === 'string' ? encoding_ : null;
var callback = maybeCallback(arguments[arguments.length - 1]); var callback = maybeCallback(arguments[arguments.length - 1]);
if (typeof options === 'function' || !options) {
options = { encoding: null, flag: 'r' };
} else if (typeof options === 'string') {
options = { encoding: options, flag: 'r' };
} else if (!options) {
options = { encoding: null, flag: 'r' };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
}
var encoding = options.encoding;
assertEncoding(encoding); assertEncoding(encoding);
// first, stat the file, so we know the size. // first, stat the file, so we know the size.
@ -178,7 +188,8 @@ fs.readFile = function(path, encoding_) {
var pos = 0; var pos = 0;
var fd; var fd;
fs.open(path, constants.O_RDONLY, 438 /*=0666*/, function(er, fd_) { var flag = options.flag || 'r';
fs.open(path, flag, 438 /*=0666*/, function(er, fd_) {
if (er) return callback(er); if (er) return callback(er);
fd = fd_; fd = fd_;
@ -243,10 +254,20 @@ fs.readFile = function(path, encoding_) {
} }
}; };
fs.readFileSync = function(path, encoding) { fs.readFileSync = function(path, options) {
if (!options) {
options = { encoding: null, flag: 'r' };
} else if (typeof options === 'string') {
options = { encoding: options, flag: 'r' };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
}
var encoding = options.encoding;
assertEncoding(encoding); assertEncoding(encoding);
var fd = fs.openSync(path, constants.O_RDONLY, 438 /*=0666*/); var flag = options.flag || 'r';
var fd = fs.openSync(path, flag, 438 /*=0666*/);
var size; var size;
var threw = true; var threw = true;
@ -888,72 +909,93 @@ function writeAll(fd, buffer, offset, length, position, callback) {
}); });
} }
fs.writeFile = function(path, data, encoding_, callback) { fs.writeFile = function(path, data, options, callback) {
var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8'); var callback = maybeCallback(arguments[arguments.length - 1]);
assertEncoding(encoding);
callback = maybeCallback(arguments[arguments.length - 1]); if (typeof options === 'function' || !options) {
fs.open(path, 'w', 438 /*=0666*/, function(openErr, fd) { options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
} else if (typeof options === 'string') {
options = { encoding: options, mode: 438, flag: 'w' };
} else if (!options) {
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
}
assertEncoding(options.encoding);
var flag = options.flag || 'w';
fs.open(path, options.flag || 'w', options.mode, function(openErr, fd) {
if (openErr) { if (openErr) {
if (callback) callback(openErr); if (callback) callback(openErr);
} else { } else {
var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data, var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data,
encoding); options.encoding || 'utf8');
writeAll(fd, buffer, 0, buffer.length, 0, callback); var position = /a/.test(flag) ? null : 0;
writeAll(fd, buffer, 0, buffer.length, position, callback);
} }
}); });
}; };
fs.writeFileSync = function(path, data, encoding) { fs.writeFileSync = function(path, data, options) {
assertEncoding(encoding); if (!options) {
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
} else if (typeof options === 'string') {
options = { encoding: options, mode: 438, flag: 'w' };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
}
var fd = fs.openSync(path, 'w'); assertEncoding(options.encoding);
var flag = options.flag || 'w';
var fd = fs.openSync(path, flag);
if (!Buffer.isBuffer(data)) { if (!Buffer.isBuffer(data)) {
data = new Buffer('' + data, encoding || 'utf8'); data = new Buffer('' + data, options.encoding || 'utf8');
} }
var written = 0; var written = 0;
var length = data.length; var length = data.length;
var position = /a/.test(flag) ? null : 0;
try { try {
while (written < length) { while (written < length) {
written += fs.writeSync(fd, data, written, length - written, written); written += fs.writeSync(fd, data, written, length - written, position);
position += written;
} }
} finally { } finally {
fs.closeSync(fd); fs.closeSync(fd);
} }
}; };
fs.appendFile = function(path, data, encoding_, callback) { fs.appendFile = function(path, data, options, callback_) {
var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8'); var callback = maybeCallback(arguments[arguments.length - 1]);
assertEncoding(encoding);
callback = maybeCallback(arguments[arguments.length - 1]); if (typeof options === 'function' || !options) {
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
} else if (typeof options === 'string') {
options = { encoding: options, mode: 438, flag: 'a' };
} else if (!options) {
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
} else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
}
fs.open(path, 'a', 438 /*=0666*/, function(err, fd) { if (!options.flag)
if (err) return callback(err); options = util._extend({ flag: 'a' }, options);
var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data, encoding); fs.writeFile(path, data, options, callback);
writeAll(fd, buffer, 0, buffer.length, null, callback);
});
}; };
fs.appendFileSync = function(path, data, encoding) { fs.appendFileSync = function(path, data, options) {
assertEncoding(encoding); if (!options) {
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
var fd = fs.openSync(path, 'a'); } else if (typeof options === 'string') {
if (!Buffer.isBuffer(data)) { options = { encoding: options, mode: 438, flag: 'a' };
data = new Buffer('' + data, encoding || 'utf8'); } else if (typeof options !== 'object') {
throw new TypeError('Bad arguments');
} }
var written = 0; if (!options.flag)
var position = null; options = util._extend({ flag: 'a' }, options);
var length = data.length;
try { fs.writeFileSync(path, data, options);
while (written < length) {
written += fs.writeSync(fd, data, written, length - written, position);
position += written; // XXX not safe with multiple concurrent writers?
}
} finally {
fs.closeSync(fd);
}
}; };
function errnoException(errorno, syscall) { function errnoException(errorno, syscall) {

11
test/simple/test-fs-append-file-sync.js

@ -73,10 +73,17 @@ assert.equal(buf.length + currentFileData.length, fileData3.length);
// test that appendFile accepts numbers. // test that appendFile accepts numbers.
var filename4 = join(common.tmpDir, 'append-sync4.txt'); var filename4 = join(common.tmpDir, 'append-sync4.txt');
fs.writeFileSync(filename4, currentFileData); fs.writeFileSync(filename4, currentFileData, { mode: m });
common.error('appending to ' + filename4); common.error('appending to ' + filename4);
fs.appendFileSync(filename4, num); var m = 0600;
fs.appendFileSync(filename4, num, { mode: m });
// windows permissions aren't unix
if (process.platform !== 'win32') {
var st = fs.statSync(filename4);
assert.equal(st.mode & 0700, m);
}
var fileData4 = fs.readFileSync(filename4); var fileData4 = fs.readFileSync(filename4);

9
test/simple/test-fs-append-file.js

@ -101,12 +101,19 @@ fs.writeFileSync(filename4, currentFileData);
common.error('appending to ' + filename4); common.error('appending to ' + filename4);
fs.appendFile(filename4, n, function(e) { var m = 0600;
fs.appendFile(filename4, n, { mode: m }, function(e) {
if (e) throw e; if (e) throw e;
ncallbacks++; ncallbacks++;
common.error('appended to file4'); common.error('appended to file4');
// windows permissions aren't unix
if (process.platform !== 'win32') {
var st = fs.statSync(filename4);
assert.equal(st.mode & 0700, m);
}
fs.readFile(filename4, function(e, buffer) { fs.readFile(filename4, function(e, buffer) {
if (e) throw e; if (e) throw e;
common.error('file4 read'); common.error('file4 read');

9
test/simple/test-fs-write-file.js

@ -76,9 +76,16 @@ fs.writeFile(filename2, buf, function(e) {
var filename3 = join(common.tmpDir, 'test3.txt'); var filename3 = join(common.tmpDir, 'test3.txt');
common.error('writing to ' + filename3); common.error('writing to ' + filename3);
fs.writeFile(filename3, n, function(e) { var m = 0600;
fs.writeFile(filename3, n, { mode: m }, function(e) {
if (e) throw e; if (e) throw e;
// windows permissions aren't unix
if (process.platform !== 'win32') {
var st = fs.statSync(filename3);
assert.equal(st.mode & 0700, m);
}
ncallbacks++; ncallbacks++;
common.error('file3 written'); common.error('file3 written');

Loading…
Cancel
Save