-
Notifications
You must be signed in to change notification settings - Fork 7.3k
fs.readFile[Sync]("/dev/stdin") does not always read the entire file. #7412
Comments
Also: I am on Mac OS X 10.8.5 and Node v0.10.26. |
The way There's really not a good way to work around that interface, as If you were just looking to read an entire stream in a single programmatic line I have a little module that will do that, under the hood it's not too dissimilar to what you came up with, but is a bit more generic for any stream: require('readtoend').readToEnd(process.stdin, function(err, data) {
console.log(data);
}); |
I want to read some input, and I don’t care whether it’s from stdin or from a file. I just want to read it (or write it), and it’s a pain to special-case these things when my operating system already provides a (mostly) transparent representation for /dev/stdin and /dev/stdout. Also, it seems possible for Node to do the “right” thing for these methods, regardless of the underlying reasons why these files are special. To illustrate this point, I’ve created a rw module that provides implementations of readFile, readFileSync, writeFile and writeFileSync that behave the way I would expect for stdin and stdout. For example, readFileSync is implemented as: module.exports = function(filename, options) {
if (filename === "/dev/stdin") {
var decoder = decode(options);
while (true) {
try {
var buffer = new Buffer(bufferSize),
bytesRead = fs.readSync(process.stdin.fd, buffer, 0, bufferSize);
} catch (e) {
if (e.code === 'EOF') break;
throw e;
}
if (bytesRead === 0) break;
decoder.push(buffer.slice(0, bytesRead));
}
return decoder.value();
} else {
return fs.readFileSync(filename, options);
}
}; (The decoder is just a simple thing for dealing with strings vs. buffers.) It’s fine if you want to push this concern to user-land, but given the complexity of doing so (as shown above), it seems to me like it would be possible to make these behave in a more reasonable way in Node and that would be a boon for users. |
I'm really confused as to why this issue was closed. When I see a function called Personally, I've always used
|
Also, presumably this interferes with the fork+open+exec+read model of reading FDs via $ node -e 'console.log(require("fs").readFileSync("/dev/fd/50", "utf8"))' 50<<< 'hello world' Okay, maybe the above is not the best example for obvious reasons, but imagine if that hadn't been just a "file" with a known size: $ node read.js <(ncat -l -p 3000) read.js: console.log(require('fs').readFileSync(process.argv[2], 'utf8')); $ ncat localhost 3000
Without readFile behaving properly, you might not
see how many cool things like this you can do.
^D |
A good example of this confusion in the real-world is in UglifyJS, the popular JavaScript minifier:
|
Regardless if many environments have If what you really wanted was a synchronous mechanism for doing so the |
You should try using fs.{read,write}{Sync}(). Not |
Thank you continuing to entertain this discussion. It has been enlightening. :) I do not consider reading synchronously to be an anti-pattern in this context: a command-line tool that takes a file as input and that needs to read the entire input before processing. There’s nothing else for the process to do while that file is loading, so forcing an asynchronous read merely adds complexity. I always assumed Node’s synchronous methods exist precisely for this type of convenience. Command-line tools invariably need to read and write to files or stdin or stdout, so an API that can handle stdin & stdout interchangeably with regular files is preferred. It needn’t be as transparent as /dev/stdin and /dev/stdout, but the lack of a (supported) synchronous API to read from stdin essentially forces any command-line tool that wants to be a good citizen to read input asynchronously, despite the availability of fs.readFileSync. If you really believe reading synchronously from stdin should not be supported, I would at least ask you make this more explicit in the documentation; otherwise fs.readFileSync("/dev/stdin") will lie in wait to bite those unaware. On the other hand if you think reading stdin synchronously is as reasonable as reading a file synchronously, then please advise on how best to implement this. |
I run into a similar issue as well. Eventually I used the byline module - I am trying to read a freshly uploaded file, even though it's marked done, sometimes not all lines were read - it's a pain that the API and the function of fs.readFile are not consistent |
Also got bitten by this. The docs give a false expectation that this should be possible: I think the docs should be updated, or the function should validate its input. |
This issue is PHP-like in the absurd brokenness of the implementation, the difficulty of doing a simple thing correctly, and the recalcitrance of the maintainers in fixing or even documenting the problem. It's eerily reminiscent in its use of this three-pronged justification:
While fingers are stuck in ears and "la la la" is sung, more and more programs written in node are going to be flaky and buggy due to the unwillingness to fix bugs in node. You want a pull request? Fine. Acknowledge that this is an actual problem. The culture of weirdly half-baked, brittle, burr-covered node modules starts here. Set a better example. In particular, the use of Quote:
There are several correct, well-documented ways to read a file in Unix systems, and you are not using one of them. |
@davidmccabe 👍 and lucky thing we ended up getting nodejs/node#1074 out of it. |
👍 |
I also just got blocked by this. |
The absence of a reliable file slurp (regardless of stdin or file source) weakens node.js for common systems-programming tasks. (Compare this to perl or bash, which make the operation trivial). |
@appersonj What absence? You're reading a bug from the 0.x series; in modern mainline Node, this was fixed about a year ago with 5ecdc03. |
Given the following complete program,
test-readFile-utf8
:And given an input file
test.txt
of 100,000 bytes, the following behaves as expected:$ ./test-readFile-utf8 < test.txt 100000
However, if the test file is piped using
cat
, the program fails to read the entire file:$ cat test.txt | ./test-readFile-utf8 65536
A complete set of test cases are available here: http://bl.ocks.org/mbostock/52950e1e53c19a56fad3
This problem can be avoided by using process.stdin’s data and end events:
However, it’s often convenient to have a single code path for reading input either from a file or from stdin — and it’s surprising that fs.readFile("/dev/stdin") (and likewise fs.readFileSync("/dev/stdin")) work sometimes but not other times — so it would be nice to make these methods work all the time as expected.
The text was updated successfully, but these errors were encountered: