Browse Source

File API tweaks

- Rename fs.cat to fs.readFile
- Move file.write to fs.writeFile
- Allow strings for the flag argument to fs.open
  ("r", "r+", "w", "w+", "a", "a+")
- Remove the unused 'File' module / class
v0.7.4-release
Tim Caswell 15 years ago
committed by Ryan Dahl
parent
commit
6115df6338
  1. 20
      doc/api.txt
  2. 157
      lib/file.js
  3. 78
      src/node.js
  4. 4
      test/mjsunit/disabled/test-fs-sendfile.js
  5. 38
      test/mjsunit/test-buffered-file.js
  6. 2
      test/mjsunit/test-eio-race.js
  7. 2
      test/mjsunit/test-eio-race2.js
  8. 2
      test/mjsunit/test-file-read-noexist.js
  9. 4
      test/mjsunit/test-fs-write.js
  10. 9
      test/mjsunit/test-stat-handler.js
  11. 2
      test/mjsunit/test-sync-fileread.js

20
doc/api.txt

@ -709,8 +709,10 @@ See the +fs.Stats+ section below for more information.
- on error: no parameters.
+fs.open(path, flags, mode)+::
+fs.open(path, flags, mode=0666)+::
See open(2). The constants like +O_CREAT+ are defined at +process.O_CREAT+.
Also you can use the strings "r", "r+", "w", "w+", "a", or "a+" as aliases
to the common flag combinations.
- on success: +fd+ is given as the parameter.
- on error: no parameters.
@ -735,11 +737,11 @@ See the +fs.Stats+ section below for more information.
- on success: returns +data, bytes_read+, what was read from the file.
- on error: no parameters.
+fs.cat(filename, encoding="utf8")+::
+fs.readFile(filename, encoding="utf8")+::
Outputs the entire contents of a file. Example:
+
--------------------------------
fs.cat("/etc/passwd").addCallback(function (content) {
fs.readFile("/etc/passwd").addCallback(function (content) {
sys.puts(content);
});
--------------------------------
@ -747,6 +749,18 @@ fs.cat("/etc/passwd").addCallback(function (content) {
- on success: returns +data+, what was read from the file.
- on error: no parameters.
+fs.writeFile(filename, data, encoding="utf8")+::
Writes data to a file. Example:
+
--------------------------------
fs.writeFile("message.txt", "Hello Node").addCallback(function () {
sys.puts("It's saved!");
});
--------------------------------
+
- on success: no parameters.
- on error: no parameters.
==== +fs.Stats+
Objects returned from +fs.stat()+ are of this type.

157
lib/file.js

@ -1,156 +1 @@
var fs = require("./fs");
var events = require('events');
/*jslint onevar: true, undef: true, eqeqeq: true, plusplus: true, regexp: true, newcap: true, immed: true */
/*globals exports, node, __filename */
exports.debugLevel = 0; // Increase to get more verbose debug output
function debugMessage (msg) {
if (exports.debugLevel > 0) {
process.error(__filename + ": " + msg.toString());
}
}
function debugObject (obj) {
if (exports.debugLevel > 0) {
process.error(__filename + ": " + JSON.stringify(obj));
}
}
exports.read = fs.cat;
exports.write = function (filename, data, encoding) {
var promise = new events.Promise();
encoding = encoding || "utf8"; // default to utf8
fs.open(filename, process.O_WRONLY | process.O_TRUNC | process.O_CREAT, 0666)
.addCallback(function (fd) {
function doWrite (_data) {
fs.write(fd, _data, 0, encoding)
.addErrback(function () {
fs.close(fd);
promise.emitError();
})
.addCallback(function (written) {
if (written === _data.length) {
fs.close(fd);
promise.emitSuccess();
} else {
doWrite(_data.slice(written));
}
});
}
doWrite(data);
})
.addErrback(function () {
promise.emitError();
});
return promise;
};
exports.File = function (filename, mode, options) {
var self = this;
options = options || {};
self.encoding = options.encoding || "utf8";
self.filename = filename;
self.actionQueue = [];
self.currentAction = null;
switch (mode) {
case "r":
self.flags = process.O_RDONLY;
break;
case "r+":
self.flags = process.O_RDWR;
break;
case "w":
self.flags = process.O_CREAT | process.O_TRUNC | process.O_WRONLY;
break;
case "w+":
self.flags = process.O_CREAT | process.O_TRUNC | process.O_RDWR;
break;
case "a":
self.flags = process.O_APPEND | process.O_CREAT | process.O_WRONLY;
break;
case "a+":
self.flags = process.O_APPEND | process.O_CREAT | process.O_RDWR;
break;
default:
throw new Error("Unknown mode");
}
self.open(self.filename, self.flags, 0666).addCallback(function (fd) {
debugMessage(self.filename + " opened. fd = " + fd);
self.fd = fd;
}).addErrback(function () {
self.emit("error", ["open"]);
});
};
var proto = exports.File.prototype;
proto._maybeDispatch = function () {
var self, args, method, promise, userPromise;
self = this;
if (self.currentAction) { return; }
self.currentAction = self.actionQueue.shift();
if (!self.currentAction) { return; }
debugObject(self.currentAction);
args = self.currentAction.args || [];
method = self.currentAction.method;
if (method !== "open") {
args.unshift(self.fd);
}
if (!args[3] && (method === "read" || method === "write")) {
args[3] = self.encoding;
}
promise = fs[method].apply(self, args);
userPromise = self.currentAction.promise;
promise.addCallback(function () {
process.assert(self.currentAction.promise === userPromise);
userPromise.emitSuccess.apply(userPromise, arguments);
self.currentAction = null;
self._maybeDispatch();
}).addErrback(function () {
debugMessage("Error in method " + method);
process.assert(self.currentAction.promise === userPromise);
userPromise.emitError.apply(userPromise, arguments);
self.currentAction = null;
self._maybeDispatch();
});
};
proto._queueAction = function (method, args) {
var userPromise = new events.Promise();
this.actionQueue.push({ method: method, args: args, promise: userPromise });
this._maybeDispatch();
return userPromise;
};
(["open", "write", "read", "close"]).forEach(function (name) {
proto[name] = function () {
return this._queueAction(name, Array.prototype.slice.call(arguments, 0));
};
});
throw new Error("The 'file' module has been removed. 'file.read' is now 'fs.readFile', and 'file.write' is now 'fs.writeFile'.");

78
src/node.js

@ -527,6 +527,23 @@ var fsModule = createInternalModule("fs", function (exports) {
};
}
// Used by fs.open and friends
function stringToFlags(flag) {
// Only mess with strings
if (typeof flag !== 'string') {
return flag;
}
switch (flag) {
case "r": return process.O_RDONLY;
case "r+": return process.O_RDWR;
case "w": return process.O_CREAT | process.O_TRUNC | process.O_WRONLY;
case "w+": return process.O_CREAT | process.O_TRUNC | process.O_RDWR;
case "a": return process.O_APPEND | process.O_CREAT | process.O_WRONLY;
case "a+": return process.O_APPEND | process.O_CREAT | process.O_RDWR;
default: throw new Error("Unknown file open flag: " + flag);
}
}
// Yes, the follow could be easily DRYed up but I provide the explicit
// list to make the arguments clear.
@ -541,13 +558,15 @@ var fsModule = createInternalModule("fs", function (exports) {
};
exports.open = function (path, flags, mode) {
if (mode === undefined) { mode = 0666; }
var promise = new events.Promise();
process.fs.open(path, flags, mode, callback(promise));
process.fs.open(path, stringToFlags(flags), mode, callback(promise));
return promise;
};
exports.openSync = function (path, flags, mode) {
return process.fs.open(path, flags, mode);
if (mode === undefined) { mode = 0666; }
return process.fs.open(path, stringToFlags(flags), mode);
};
exports.read = function (fd, length, position, encoding) {
@ -654,13 +673,54 @@ var fsModule = createInternalModule("fs", function (exports) {
return process.fs.unlink(path);
};
exports.writeFile = function (path, data, encoding) {
var promise = new events.Promise();
encoding = encoding || "utf8"; // default to utf8
fs.open(path, "w")
.addCallback(function (fd) {
function doWrite (_data) {
fs.write(fd, _data, 0, encoding)
.addErrback(function () {
fs.close(fd);
promise.emitError();
})
.addCallback(function (written) {
if (written === _data.length) {
fs.close(fd);
promise.emitSuccess();
} else {
doWrite(_data.slice(written));
}
});
}
doWrite(data);
})
.addErrback(function () {
promise.emitError();
});
return promise;
};
exports.writeFileSync = function (path, data, encoding) {
encoding = encoding || "utf8"; // default to utf8
var fd = exports.openSync(path, "w");
return process.fs.write(fd, data, 0, encoding);
};
exports.cat = function () {
throw new Error("fs.cat is deprecated. Please use fs.readFile instead.");
};
exports.cat = function (path, encoding) {
exports.readFile = function (path, encoding) {
var promise = new events.Promise();
encoding = encoding || "utf8"; // default to utf8
exports.open(path, process.O_RDONLY, 0666).addCallback(function (fd) {
exports.open(path, "r").addCallback(function (fd) {
var content = "", pos = 0;
function readChunk () {
@ -689,11 +749,15 @@ var fsModule = createInternalModule("fs", function (exports) {
return promise;
};
exports.catSync = function (path, encoding) {
exports.catSync = function () {
throw new Error("fs.catSync is deprecated. Please use fs.readFileSync instead.");
};
exports.readFileSync = function (path, encoding) {
encoding = encoding || "utf8"; // default to utf8
var
fd = exports.openSync(path, process.O_RDONLY, 0666),
fd = exports.openSync(path, "r"),
content = '',
pos = 0,
r;
@ -939,7 +1003,7 @@ function cat (id, loadPromise) {
loadPromise.emitError(new Error("could not load core module \"http\""));
});
} else {
promise = fs.cat(id);
promise = fs.readFile(id);
}
return promise;

4
test/mjsunit/disabled/test-fs-sendfile.js

@ -19,8 +19,8 @@ server.listen(PORT);
var client = tcp.createConnection(PORT);
client.addListener("connect", function () {
posix.open(x,process.O_RDONLY, 0666).addCallback(function (fd) {
posix.sendfile(client.fd, fd, 0, expected.length).addCallback(function (size) {
fs.open(x, 'r').addCallback(function (fd) {
fs.sendfile(client.fd, fd, 0, expected.length).addCallback(function (size) {
assert.equal(expected.length, size);
});
});

38
test/mjsunit/test-buffered-file.js

@ -1,38 +0,0 @@
process.mixin(require("./common"));
var testTxt = path.join(fixturesDir, "test.txt");
var libDir = path.join(testDir, "../../lib");
require.paths.unshift(libDir);
process.mixin(require("file"));
var fileUnlinked = false;
var file = new File(testTxt, "w+");
file.write("hello\n");
file.write("world\n");
setTimeout(function () {
file.write("hello\n");
file.write("world\n");
file.close().addCallback(function () {
error("file closed...");
var out = fs.cat(testTxt).wait();
print("the file contains: ");
p(out);
assert.equal("hello\nworld\nhello\nworld\n", out);
var file2 = new File(testTxt, "r");
file2.read(5).addCallback(function (data) {
puts("read(5): " + JSON.stringify(data));
assert.equal("hello", data);
fs.unlink(testTxt).addCallback(function () {
fileUnlinked = true;
});
});
file2.close();
});
}, 10);
process.addListener("exit", function () {
assert.equal(true, fileUnlinked);
puts("done");
});

2
test/mjsunit/test-eio-race.js

@ -36,7 +36,7 @@ function tryToKillEventLoop() {
// Generate a lot of thread pool events
var pos = 0;
fs.open('/dev/zero', process.O_RDONLY, 0666).addCallback(function (rd) {
fs.open('/dev/zero', "r").addCallback(function (rd) {
function readChunk () {
fs.read(rd, 1024, pos, 'binary').addCallback(function (chunk, bytesRead) {
if (chunk) {

2
test/mjsunit/test-eio-race2.js

@ -8,7 +8,7 @@ setTimeout(function () {
N = 30;
for (var i=0; i < N; i++) {
puts("start " + i);
fs.cat(testTxt).addCallback(function(data) {
fs.readFile(testTxt).addCallback(function(data) {
puts("finish");
}).addErrback(function (e) {
puts("error! " + e);

2
test/mjsunit/test-file-cat-noexist.js → test/mjsunit/test-file-read-noexist.js

@ -2,7 +2,7 @@ process.mixin(require("./common"));
var got_error = false;
var filename = path.join(fixturesDir, "does_not_exist.txt");
var promise = fs.cat(filename, "raw");
var promise = fs.readFile(filename, "raw");
promise.addCallback(function (content) {
debug("cat returned some content: " + content);

4
test/mjsunit/test-fs-write.js

@ -4,10 +4,10 @@ var fn = path.join(fixturesDir, "write.txt");
var expected = "hello";
var found;
fs.open(fn, process.O_WRONLY | process.O_TRUNC | process.O_CREAT, 0644).addCallback(function (file) {
fs.open(fn, 'w', 0644).addCallback(function (file) {
fs.write(file, expected, 0, "utf8").addCallback(function() {
fs.close(file).addCallback(function() {
fs.cat(fn, process.UTF8).addCallback(function(contents) {
fs.readFile(fn, process.UTF8).addCallback(function(contents) {
found = contents;
fs.unlink(fn).wait();
});

9
test/mjsunit/test-stat-handler.js

@ -16,12 +16,11 @@ process.watchFile(f, function (curr, prev) {
});
var File = require("file").File;
var file = new File(f, 'w+');
file.write('xyz\n');
file.close().wait();
var fs = require("fs");
var fd = fs.openSync(f, "w+");
fs.writeSync(fd, 'xyz\n');
fs.closeSync(fd);
process.addListener("exit", function () {
assert.equal(true, changes > 0);

2
test/mjsunit/test-sync-cat.js → test/mjsunit/test-sync-fileread.js

@ -2,4 +2,4 @@ process.mixin(require('./common'));
var fixture = path.join(__dirname, "fixtures/x.txt");
assert.equal("xyz\n", fs.catSync(fixture));
assert.equal("xyz\n", fs.readFileSync(fixture));
Loading…
Cancel
Save