简体   繁体   English

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

[英]Fastest way to copy a file in Node.js

The project that I am working on (Node.js) implies lots of operations with the file system (copying, reading, writing, etc.).我正在从事的项目 (Node.js) 涉及对文件系统的大量操作(复制、读取、写入等)。

Which methods are the fastest?哪些方法最快?

Use the standard built-in way fs.copyFile :使用标准的内置方式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');
});

If you have to support old end-of-life versions of Node.js - here is how you do it in versions that do not support fs.copyFile :如果您必须支持旧的 Node.js 生命周期结束版本 - 以下是在不支持fs.copyFile的版本中如何做到这一点:

const fs = require('fs');
fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));

Same mechanism, but this adds error handling:相同的机制,但这增加了错误处理:

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;
    }
  }
}

Since Node.js 8.5.0 we have the new fs.copyFile and fs.copyFileSync methods.从 Node.js 8.5.0 开始,我们有了新的fs.copyFilefs.copyFileSync方法。

Usage example:使用示例:

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');
});

I was not able to get the createReadStream/createWriteStream method working for some reason, but using the fs-extra npm module it worked right away.由于某种原因,我无法使createReadStream/createWriteStream方法工作,但使用fs-extra npm 模块它立即工作。 I am not sure of the performance difference though.我不确定性能差异。

npm install --save fs-extra

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

fs.copySync(path.resolve(__dirname, './init/xxx.json'), 'xxx.json');

Fast to write and convenient to use, with promise and error management:编写速度快,使用方便,具有承诺和错误管理:

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;
  });
}

The same with async/await syntax:与 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;
  }
}

Well, usually it is good to avoid asynchronous file operations.嗯,通常最好避免异步文件操作。 Here is the short (ie no error handling) sync example:这是简短的(即没有错误处理)同步示例:

var fs = require('fs');
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));

If you don't care about it being async, and aren't copying gigabyte-sized files, and would rather not add another dependency just for a single function:如果您不关心它是异步的,并且不复制千兆字节大小的文件,并且宁愿不为单个功能添加另一个依赖项:

function copySync(src, dest) {
  var data = fs.readFileSync(src);
  fs.writeFileSync(dest, data);
}

Mike Schilling's solution with error handling with a shortcut for the error event handler. Mike Schilling 的错误处理解决方案和错误事件处理程序的快捷方式。

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

  var rd = fs.createReadStream(source);
  rd.on("error", done);

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

  function done(err) {
    if (!cbCalled) {
      cb(err);
      cbCalled = true;
    }
  }
}

You may want to use async/await, since node v10.0.0 it's possible with the built-in fs Promises API .您可能想要使用异步/等待,因为node v10.0.0可以使用内置的fs Promises API

Example:例子:

const fs = require('fs')

const copyFile = async (src, dest) => {
  await fs.promises.copyFile(src, dest)
}

Note:笔记:

As of node v11.14.0, v10.17.0 the API is no longer experimental.node v11.14.0, v10.17.0 ,API 不再是实验性的。

More information:更多信息:

Promises API承诺 API

Promises copyFile 承诺复制文件

   const fs = require("fs");
   fs.copyFileSync("filepath1", "filepath2"); //fs.copyFileSync("file1.txt", "file2.txt");

This is what I personally use to copy a file and replace another file using Node.js:)这是我个人使用 Node.js 复制文件和替换另一个文件的方式:)

For fast copies you should use the fs.constants.COPYFILE_FICLONE flag.对于快速复制,您应该使用fs.constants.COPYFILE_FICLONE标志。 It allows (for filesystems that support this) to not actually copy the content of the file.它允许(对于支持此功能的文件系统)不实际复制文件的内容。 Just a new file entry is created, but it points to aCopy-on-Write "clone" of the source file.只是创建了一个新文件条目,但它指向源文件的写时复制“克隆”。

To do nothing/less is the fastest way of doing something;)什么都不做/少做是做某事的最快方式;)

https://nodejs.org/api/fs.html#fs_fs_copyfile_src_dest_flags_callback https://nodejs.org/api/fs.html#fs_fs_copyfile_src_dest_flags_callback

let fs = require("fs");

fs.copyFile(
  "source.txt",
  "destination.txt",
  fs.constants.COPYFILE_FICLONE,
  (err) => {
    if (err) {
      // TODO: handle error
      console.log("error");
    }
    console.log("success");
  }
);

Using promises instead:改用承诺:

let fs = require("fs");
let util = require("util");
let copyFile = util.promisify(fs.copyFile);


copyFile(
  "source.txt",
  "destination.txt",
  fs.constants.COPYFILE_FICLONE
)
  .catch(() => console.log("error"))
  .then(() => console.log("success"));

Use Node.js's built-in copy function使用 Node.js 内置的复制功能

It provides both async and sync version:它同时提供异步和同步版本:

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');
});

fs.copyFileSync(src, dest[, mode]) fs.copyFileSync(src, dest[, mode])

The project that I am working on (Node.js) implies lots of operations with the file system (copying, reading, writing, etc.).我正在处理的项目(Node.js)包含文件系统的许多操作(复制,读取,写入等)。

Which methods are the fastest?哪些方法最快?

You can do it using the fs-extra module very easily:您可以使用fs-extra模块非常轻松地做到这一点:

const fse = require('fs-extra');

let srcDir = 'path/to/file';
let destDir = 'pat/to/destination/directory';

fse.moveSync(srcDir, destDir, function (err) {

    // To move a file permanently from a directory
    if (err) {
        console.error(err);
    } else {
        console.log("success!");
    }
});

Or要么

fse.copySync(srcDir, destDir, function (err) {

     // To copy a file from a directory
     if (err) {
         console.error(err);
     } else {
         console.log("success!");
     }
});

I wrote a little utility to test the different methods:我写了一个小工具来测试不同的方法:

https://www.npmjs.com/package/copy-speed-test https://www.npmjs.com/package/copy-speed-test

run it with运行它

npx copy-speed-test --source someFile.zip --destination someNonExistentFolder

It does a native copy using child_process.exec(), a copy file using fs.copyFile and it uses createReadStream with a variety of different buffer sizes (you can change buffer sizes by passing them on the command line. run npx copy-speed-test -h for more info).它使用 child_process.exec() 进行本机复制,使用 fs.copyFile 进行复制文件,并使用具有各种不同缓冲区大小的 createReadStream(您可以通过在命令行上传递它们来更改缓冲区大小。运行 npx copy-speed-测试 -h 以获得更多信息)。

Mike's solution , but with promises:迈克的解决方案,但有承诺:

const FileSystem = require('fs');

exports.copyFile = function copyFile(source, target) {
    return new Promise((resolve,reject) => {
        const rd = FileSystem.createReadStream(source);
        rd.on('error', err => reject(err));
        const wr = FileSystem.createWriteStream(target);
        wr.on('error', err => reject(err));
        wr.on('close', () => resolve());
        rd.pipe(wr);
    });
};

Improvement of one other answer.改进另一个答案。

Features:特征:

  • If the dst folders do not exist, it will automatically create it.如果 dst 文件夹不存在,它会自动创建它。 The other answer will only throw errors.另一个答案只会抛出错误。
  • It returns a promise , which makes it easier to use in a larger project.它返回一个promise ,这使得它更容易在更大的项目中使用。
  • It allows you to copy multiple files, and the promise will be done when all of them are copied.它允许你复制多个文件,当所有文件都被复制时,承诺就会完成。

Usage:用法:

var onePromise = copyFilePromise("src.txt", "dst.txt");
var anotherPromise = copyMultiFilePromise(new Array(new Array("src1.txt", "dst1.txt"), new Array("src2.txt", "dst2.txt")));

Code:代码:

function copyFile(source, target, cb) {
    console.log("CopyFile", source, target);

    var ensureDirectoryExistence = function (filePath) {
        var dirname = path.dirname(filePath);
        if (fs.existsSync(dirname)) {
            return true;
        }
        ensureDirectoryExistence(dirname);
        fs.mkdirSync(dirname);
    }
    ensureDirectoryExistence(target);

    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;
        }
    }
}

function copyFilePromise(source, target) {
    return new Promise(function (accept, reject) {
        copyFile(source, target, function (data) {
            if (data === undefined) {
                accept();
            } else {
                reject(data);
            }
        });
    });
}

function copyMultiFilePromise(srcTgtPairArr) {
    var copyFilePromiseArr = new Array();
    srcTgtPairArr.forEach(function (srcTgtPair) {
        copyFilePromiseArr.push(copyFilePromise(srcTgtPair[0], srcTgtPair[1]));
    });
    return Promise.all(copyFilePromiseArr);
}

The project that I am working on (Node.js) implies lots of operations with the file system (copying, reading, writing, etc.).我正在处理的项目(Node.js)包含文件系统的许多操作(复制,读取,写入等)。

Which methods are the fastest?哪些方法最快?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM