【问题标题】:How do I redirect asynchronous output to a file?如何将异步输出重定向到文件?
【发布时间】:2015-05-06 01:58:51
【问题描述】:

我有一个 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,但是处理这个问题的正确方法是什么?

【问题讨论】:

  • 当您检查记事本时,您认为文件句柄仍然打开吗?如果我没记错,只要文件句柄打开,数据并没有真正写入文件,尽管在调试期间步骤它可能会说写作已经完成。 (从 c# 的角度来看),记事本也是出了名的不可靠(在目视检查期间),因为即使文件本身打开,您也可以删除记事本。
  • 跟nodejs没关系。这就是外壳的工作方式。这样做的传统方式是node transform.js myfile > tmp;mv tmp myfile

标签: javascript node.js asynchronous console.log


【解决方案1】:

问题实际上不在 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)。

【讨论】:

  • shell中传统的解决方案是cat myfile.txt > tmp; mv tmp myfile.txt
  • 谢谢,我已将其添加为答案末尾的选项。
【解决方案2】:

问题是

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

我认为你想要的是:

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

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

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) 使用“流”

这确实是最好的方法。特别是如果你想学习 Node.js

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

到最后,你会拥有这些问题。

祝你好运!

【讨论】:

  • 我很好奇为什么投反对票?是因为提议的解决方案都不能真正解决问题吗?
  • 这里的所有解决方案(我的和 Trott 的)都有效。 Trott 在 bash 中工作,这是最简单的可能工作的好方法。我使用节点的功能来解决问题。这仅取决于您想做什么。为什么投反对票?因为仇恨者必须讨厌:-)
猜你喜欢
  • 2012-08-26
  • 1970-01-01
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-29
  • 2012-06-26
  • 2017-04-04
相关资源
最近更新 更多