如何将异步输出重定向到文件?

How do I redirect asynchronous output to a file?

我有一个 Node.js 脚本,它读取文件的内容,对其内容进行一些转换,并记录输出:

var transformer = require('./transformer'),
    fs = require('fs'),
    file = process.argv[2];

if (!file) {
    throw 'no file specified\n';
}

fs.readFile(file, 'utf-8', function (err, data) {
    if (err) {
        throw err;
    }

    transformer.transform(data, function (text) {
        console.log(text);
    });
});

这很好用:

$ node transform.js myfile.txt

这有效:

$ node transform.js myfile.txt > anotherfile.txt

但是,当我尝试将输出重定向到我正在读取的同一个文件时,该文件变为空白:

$ node transform.js myfile.txt > myfile.txt

同样的事情使用 tee:

$ node transform.js myfile.txt | tee myfile.txt

奇怪的是,这有效:

$ node transform.js myfile.txt >> myfile.txt

但我不想附加到文件 - 我想覆盖它的内容。

我认为问题在于,由于 fs.readFile 是异步的,因此 console.log 也被异步调用 - 即,它获取数据块而不是一次获取所有数据。我想我可以改用 fs.readFileSync,但是处理这个问题的正确方法是什么?

问题是

  • 您正在打开文件进行阅读,
  • 然后打开文件进行写入(清空),
  • 然后从一个空文件中读取。
  • 什么都不改变
  • 什么都不写

我认为你想要的是:

  • 开放阅读
  • 读取和缓冲
  • 变换
  • 打开写入

有几种方法可以做到这一点:

1) 同步读取文件。 Node.js 0.12 supports this.

var transformer = require('./transformer'),
    fs = require('fs'),
    file = process.argv[2];

if (!file) {
    throw 'no file specified\n';
}

fs.readFileSync(file, 'utf-8', function (err, data) {
    if (err) {
        throw err;
    }

    transformer.transform(data, function (text) {
        console.log(text);
    });
});

2) 使用"streams"

这真是最好的办法。特别是如果你想学习 Node.js

据我所知,学习流的最好方法是从 NodeSchool:http://nodeschool.io/#workshoppers 试试 stream-adventure

到最后,您将拥有这些类型的问题。

祝你好运!

问题实际上不在 Node 中,而是在 shell 中。当您使用 > 重定向时,shell 做的第一件事是打开文件进行写入,清空文件。您的程序会从该空文件中读取,在您的情况下,空输入意味着空输出。

无论 myfile.txt 的初始内容如何,​​这也会导致一个空文件:

$ cat myfile.txt > myfile.txt 

一种解决方案是在 Node 脚本中写入文件,而不是使用重定向。您已经在那里指定和读取文件,那么为什么不在 argv 中指定一个输出文件并写入它而不是使用 shell 重定向?请注意构建代码,以便读取和写入同一文件。

正如@slebetman 在评论中指出的那样,另一种解决方案是 cat myfile.txt > tmp; mv tmp myfile.txt(或者我的首选:cat myfile.txt > tmp && mv tmp myfile.txt)。