Listen to (own) process.stdout (in Node.js)
Asked Answered
F

2

7

Probably a basic question for those familiar with the topic. Consider the following toy program:

  const fs = require('fs');
  process.stdout.on('data', (chunk) => {
    fs.writeFileSync('myfile.txt', chunk, 'utf-8'); // just an example
  });
  process.stdout.write('xyz');

If I run this code just as it is, I get the following error:

  errno: -4053,
  code: 'ENOTCONN',
  syscall: 'read'

I already do not understand why that happens. But it gets even stranger:

When I run the code with a console.log() before it, no error is thrown anymore! However, the listener I defined for the data event seems not to be executed in that case, as no text file is created.

Can someone explain to me why this happens and what I can do get the expected result (here write to myfile.txt)?

Finbar answered 9/12, 2021 at 15:2 Comment(0)
R
3

The first error you see is caused by trying to connect to stdout to get its data. You haven't written anything to stdout, so it's not initialized, so you can't connect to it! ENOTCONN means exactly that: Error: Not Connected (to the stdout socket).

Now, for the second error. console.log() is an alias for process.stdout.write('\n'). So when you run the code with a console.log() before it, you've now initialized stdout, so you can connect to it and no ENOTCONN error will be thrown. But you're waiting for input to come from the console from stdout. Input doesn't come from stdout; it comes from stdin.

To fix this, you need to:

  1. Initialize stdin before connecting to it, using process.stdin.resume().
  2. Wait for data from stdin rather than stdout, using process.stdin.on(...).
  3. Exit the program successfully when you're done receiving input from stdin, using process.exit(0).
const fs = require('fs')

process.stdin.resume()
process.stdin.on('data', (chunk) => {
  fs.writeFileSync('mytestfile.txt', chunk, 'utf-8')

  // Uncomment the following line if you want to write
  // something to the console to indicate success
  // process.stdout.write("Got your input!")

  process.exit(0)
})
Rriocard answered 18/1, 2023 at 20:37 Comment(2)
so is there no way to catch the result of all the things that are getting printed on console and write them in the file? imagine we write console.log('foo') and our code catch foo and write it in our file.Whirlabout
If you're asking about capturing console output from only this Node program, #47658913 gives a couple good answers!Rriocard
N
0

The error you're seeing is occurring because the data event is not being emitted by the process.stdout stream. This means that the listener you've defined is not being called, and thus the writeFileSync call is not being executed.

As for why adding a console.log() resolves the issue, it's likely that the console.log call is causing the event loop to run, which in turn causes the data event to be emitted.

In order to get the expected result of writing to myfile.txt, you should try using the 'end' event instead of the 'data' event. This event is emitted when there is no more data to be read from the stream.

Try this:

process.stdout.on('end', () => {
    fs.writeFileSync('myfile.txt', 'xyz', 'utf-8');
});
process.stdout.end();

This will write the string 'xyz' to myfile.txt when the 'end' event is emitted. Another alternative would be to directly write to the file before the stdout.write()

fs.writeFileSync('myfile.txt', 'xyz', 'utf-8');
process.stdout.write('xyz');

Either way, it will ensure that your file is written before the process exits.

Nordstrom answered 19/1, 2023 at 13:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.