在 Node.js 中复制文件的最快方法

IT技术 javascript node.js
2021-02-03 21:00:38

我正在从事的项目 (Node.js) 意味着对文件系统进行大量操作(复制、读取、写入等)。

哪些方法最快?

6个回答

使用标准内置方式fs.copyFile

const fs = require('fs');

// File destination.txt will be created or overwritten by default.
fs.copyFile('source.txt', 'destination.txt', (err) => {
  if (err) throw err;
  console.log('source.txt was copied to destination.txt');
});

如果您必须支持旧的废弃 Node.js 版本 - 以下是在不支持的版本中执行此操作的方法fs.copyFile

const fs = require('fs');
fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));
请记住,在现实生活中,您需要同时检查createReadStreamcreateWriteStream错误,因此您不会得到单行(尽管它仍然会一样快)。
2021-03-16 21:00:38
Wellcopy在 Window 上不可移植,这与完整的 Node.js 解决方案相反。
2021-03-21 21:00:38
不幸的是,与 child_process.execFile('/bin/cp', ['--no-target-directory', source, target]).
2021-03-22 21:00:38
我使用了这种方法,我得到的只是一个空白文件。任何想法为什么?fs.createReadStream('./init/xxx.json').pipe(fs.createWriteStream('xxx.json'));
2021-04-04 21:00:38
这比执行原始cp test.log newLog.logvia快/慢多少require('child_process').exec
2021-04-10 21:00:38

相同的机制,但这增加了错误处理:

function copyFile(source, target, cb) {
  var cbCalled = false;

  var rd = fs.createReadStream(source);
  rd.on("error", function(err) {
    done(err);
  });
  var wr = fs.createWriteStream(target);
  wr.on("error", function(err) {
    done(err);
  });
  wr.on("close", function(ex) {
    done();
  });
  rd.pipe(wr);

  function done(err) {
    if (!cbCalled) {
      cb(err);
      cbCalled = true;
    }
  }
}
代表什么cb我们应该传入什么作为第三个参数?
2021-03-16 21:00:38
值得注意的是需要 cbCalled 标志,因为管道错误会在两个流上触发错误。源和目标流。
2021-03-17 21:00:38
如果源文件不存在,您如何处理错误?在这种情况下仍会创建目标文件。
2021-03-28 21:00:38
我认为中的错误WriteStream只会取消它。你必须给rd.destroy()自己打电话至少这就是发生在我身上的事情。遗憾的是,除了源代码之外,没有太多文档。
2021-03-29 21:00:38
@SaiyanGirl 'cb' 代表“回调”。你应该传入一个函数。
2021-04-06 21:00:38

createReadStream/createWriteStream由于某种原因,我无法使该方法起作用,但是使用fs-extra npm module它立即起作用了。虽然我不确定性能差异。

npm install --save fs-extra

var fs = require('fs-extra');

fs.copySync(path.resolve(__dirname, './init/xxx.json'), 'xxx.json');
这是现在最好的选择
2021-03-14 21:00:38
fs-extra 也有异步方法,即fs.copy(src, dst, callback);,这些应该可以解决@mvillar 的问题。
2021-03-25 21:00:38
在节点中使用同步代码会降低您的应用程序性能。
2021-03-29 21:00:38
哦,拜托...问题是关于复制文件的最快方法。虽然最快总是主观的,但我认为同步代码在这里没有任何意义。
2021-04-05 21:00:38
最快实施还是最快执行?不同的优先级意味着这是一个有效的答案。
2021-04-11 21:00:38

从 Node.js 8.5.0 开始,我们有了新的fs.copyFilefs.copyFileSync方法。

用法示例:

var fs = require('fs');

// File "destination.txt" will be created or overwritten by default.
fs.copyFile('source.txt', 'destination.txt', (err) => {
    if (err) 
        throw err;
    console.log('source.txt was copied to destination.txt');
});
这是页面上唯一正确的答案。其他答案都没有实际复制文件。MacOS 和 Windows 上的文件还有其他元数据,这些元数据仅通过复制字节就会丢失。此页面、windowsmacos上的任何其他答案未复制的数据示例即使在 Unix 上,另一个答案也不会复制创建日期,这在复制文件时通常很重要。
2021-03-21 21:00:38
很遗憾,这无法复制 mac 上的所有内容。希望他们会修复它:github.com/nodejs/node/issues/30575
2021-03-26 21:00:38
顺便说一句,请记住copyFile()在覆盖较长的文件时被窃听。感谢uv_fs_copyfile()直到 Node v8.7.0 (libuv 1.15.0)。github.com/libuv/libuv/pull/1552
2021-04-06 21:00:38

编写快速,使用方便,具有Promise和错误管理:

function copyFile(source, target) {
  var rd = fs.createReadStream(source);
  var wr = fs.createWriteStream(target);
  return new Promise(function(resolve, reject) {
    rd.on('error', reject);
    wr.on('error', reject);
    wr.on('finish', resolve);
    rd.pipe(wr);
  }).catch(function(error) {
    rd.destroy();
    wr.end();
    throw error;
  });
}

与 async/await 语法相同:

async function copyFile(source, target) {
  var rd = fs.createReadStream(source);
  var wr = fs.createWriteStream(target);
  try {
    return await new Promise(function(resolve, reject) {
      rd.on('error', reject);
      wr.on('error', reject);
      wr.on('finish', resolve);
      rd.pipe(wr);
    });
  } catch (error) {
    rd.destroy();
    wr.end();
    throw error;
  }
}
一旦复制成功,Promise就会得到解决。如果它被拒绝,它的状态就被解决了,多次调用拒绝不会有什么区别。
2021-03-12 21:00:38
如果你想知道为什么你的应用程序在管道错误后永远不会关闭/dev/stdin,这是一个错误github.com/joyent/node/issues/25375
2021-03-12 21:00:38
当没有更多输入存在(损坏的网络共享)但写入仍然成功时会发生什么?拒绝(从读)和解决(从写)都会被调用吗?如果读/写都失败(读时坏磁盘扇区,写时满磁盘)怎么办?然后拒绝将被调用两次。基于 Mike 带有标志的回答的 Promise 解决方案(不幸的是)似乎是正确考虑错误处理的唯一可行解决方案。
2021-03-17 21:00:38
我刚刚测试new Promise(function(resolve, reject) { resolve(1); resolve(2); reject(3); reject(4); console.log("DONE"); }).then(console.log.bind(console), function(e){console.log("E", e);});并查找了有关此规范,您是对的:尝试解决或拒绝已解决的Promise没有效果。也许您可以扩展您的答案并解释为什么以这种方式编写函数?谢谢 :-)
2021-03-26 21:00:38
顺便说一句,close应该finish用于可写流。
2021-04-05 21:00:38