【问题标题】:File not closing in node.js before upload上传前文件未在 node.js 中关闭
【发布时间】:2016-08-23 13:21:59
【问题描述】:

我正在尝试在创建后将文件上传到 S3,但是该文件似乎没有通过 fs.createWriteStream 关​​闭。因此,我不断上传一个 0 字节的文件。

function createManifest(manfile) {
console.log(['a'].toString(), ['a', 'b'].toString());

    var arrayLength = files.length;
    var lastItem = arrayLength - 1;
    console.log( chalk.blue("The last item value is:",lastItem))
    console.log( chalk.yellow("The arrayLength value is:",arrayLength))
    var logStream = fs.createWriteStream("manny_temp.json", {'flags': 'a'});
// use {'flags': 'a'} to append and {'flags': 'w'} to erase and write a new file
//    logStream.on('open', function(fd) {
logStream.write('{'+ "\r\n");
logStream.write("\"entries\": [" + "\r\n");

    for (var i = 0; i < arrayLength; i++) {

            console.log( chalk.inverse(files[i]))
            console.log( chalk.blue("The i value is:",i))
            if ( i == lastItem) {
                logStream.write("{\"url\":\"s3://mybucket/" +files[i] + "\",\"key\":true}" + "\r\n");
            } else {
                    logStream.write("{\"url\":\"s3://mybucket/" +files[i] + "\",\"key\":true}," + "\r\n");
             }
    }
    logStream.write('    ]' + "\r\n");
    logStream.write('}');
//      }).on('end', function() {
            logStream.end();
            //fs.renameSync(logStream.path, manfile.toString());
            return callback(filepath);
//      logStream.close();
    //fs.renameSync(logStream.path, "manny.json");

  //   });
}

我尝试了多种方法来关闭文件,以便下一个函数可以在创建时上传文件,甚至添加了睡眠,但它似乎总是留下一个挂起的 inode。

使用 fs.write 似乎只写一行而不是写数组/流数据中的所有行。

有人有什么建议吗?

【问题讨论】:

  • 请清理您的示例代码,使其一目了然。

标签: javascript node.js file fs


【解决方案1】:

您需要在调用回调之前监听logStream 上的close 事件。这就是后备文件描述符已关闭的信号(不再进行写入)。我应该注意,这与侦听finish 事件不同,因为finish 仅表示流已关闭,但不一定表示文件描述符已关闭,因此从技术上讲,如果您要去,则依赖它不太安全稍后对文件进行处理)。

替换这个:

return callback(filepath);

用这个:

logStream.on('close', function() {
  callback(filepath);
});

可以通过使用节点生态系统中常见的(err, result) 样式回调来进一步改进这一点:

logStream.on('close', function() {
  callback(null, filepath);
});
logStream.on('error', function(err) {
  callback(err);
});

这样您就可以捕获打开或写入文件可能导致的任何错误。

我还假设您确实在某个父范围内定义了callback

【讨论】:

  • 这应该可以工作。您还应该注意您看到此行为的原因。 Node.js 是异步的。所以 logStream 甚至在你的 for 循环完成它的迭代之前就结束了。考虑在实施上述措施之前进行一些研究。
  • btw callback 在 Adam 的代码中没有定义,所以他不能使用它。他的问题非常原始,应该即兴创作,否则没人能理解和回答;)
  • @AmolMKulkarni 如果callback 确实未定义,他们会在执行createManifest() 函数时立即看到异常。由于他们没有提到这样的错误,我相信可以安全地假设它可能是在父范围中定义的。
【解决方案2】:

不过,您的问题是在没有进行基础研究的情况下提出的,这是试图使其代码更具可读性和可执行性的尝试。希望您能通过以下代码找到答案。

如果您的问题仍然相同,请以更好的方式重新编写您的问题。

var chalk = require('chalk');
var fs = require('fs');

function createManifest(manfile) {
var files = ['/test.json'];
console.log(['a'].toString(), ['a', 'b'].toString());
    var arrayLength = files.length;
    var lastItem = arrayLength - 1;
    console.log( chalk.blue("The last item value is:",lastItem))
    console.log( chalk.yellow("The arrayLength value is:",arrayLength))
    var logStream = fs.createWriteStream("manny_temp.json", {'flags': 'a'});
    logStream.write('{'+ "\r\n");
    logStream.write("\"entries\": [" + "\r\n");

    for (var i = 0; i < arrayLength; i++) {

            console.log( chalk.inverse(files[i]))
            console.log( chalk.blue("The i value is:",i))
            if ( i == lastItem) {
                logStream.write("{\"url\":\"s3://mybucket/" +files[i] + "\",\"key\":true}" + "\r\n");
            } else {
                    logStream.write("{\"url\":\"s3://mybucket/" +files[i] + "\",\"key\":true}," + "\r\n");
             }
    }
    logStream.write('    ]' + "\r\n");
    logStream.write('}'); 
    logStream.end();
    logStream.on('finish', function(){
        fs.renameSync("manny_temp.json", "manny.json"); 
    }); 
};

createManifest();

【讨论】:

  • 即使用你的函数代替我的函数,我似乎仍然遇到与我之前尝试的其他修复相同的问题,这是错误:code fs.js:549 return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
  • @Adam:我认为,如果您向我们展示更多代码和您遇到的完整详细错误会更好。
【解决方案3】:

mscdex 几乎是正确的。您需要监听 'finish' 事件,而不是 'close' 事件,因为它是由可读流发出的,但这是一个可写流。

您可以将您的处理程序传递给“结束”。见https://nodejs.org/dist/latest-v4.x/docs/api/stream.html#stream_event_finish

logStream.end(function() {
    fs.renameSync("manny_temp.json", "manny.json");
    callback(filepath);
});

我试图编辑 mscdex 对此的回答,但由于某种原因被拒绝了。

编辑:您需要定义或传入“回调”以及“文件路径”。

【讨论】:

  • close 事件并非仅适用于可读文件流。实际上,可读可写文件流share the same .close() implementation,也就是where close is emitted
  • 我还应该注意,close 事件本身不是节点流的一部分,因此取决于各个流实现(例如 fs 流)在适用的情况下发出它。
  • OP 使用 fs.createWriteStream 创建 logStream,因此获取了一个 WriteStream 对象,该对象也未记录为发出“关闭”事件。 nodejs.org/dist/latest-v4.x/docs/api/…
  • close 也没有记录在fs.ReadStream 下。 close is 记录在流的Readable 流文档下,所以这实际上只是一个(无意的)文档问题。不过fs.ReadStreamfs.WriteStream 已经共享.close() 实现很长时间了,所以在此期间使用是安全的。
  • FWIW 我已经提交了关于文档 here 的问题。
猜你喜欢
  • 1970-01-01
  • 2012-10-12
  • 1970-01-01
  • 2017-12-12
  • 2018-08-20
  • 1970-01-01
  • 2014-12-05
  • 2020-07-06
  • 2011-08-24
相关资源
最近更新 更多