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

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

哪种方法是最快的?

482001 次浏览

使用标准的内置方式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'));

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

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

通常避免异步文件操作是很好的。以下是一个简短的(即没有错误处理)同步示例:

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

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

由于某些原因,我无法让createReadStream/createWriteStream方法工作,但使用fs-extra npm模块它立即工作。但我不确定性能上的差异。

# EYZ0

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


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

编写速度快,使用方便,有承诺和错误管理:

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

如果你不关心它是否是异步的,并且不复制千兆字节大小的文件,并且宁愿不为单个函数添加另一个依赖项:

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

迈克的解决方案,但承诺:

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

另一个答案的改进。

特点:

  • 如果dst文件夹不存在,则会自动创建。另一个答案只会抛出错误。
  • 它返回promise,这使它更容易在较大的项目中使用。
  • 它允许您复制多个文件,当所有文件都被复制时,承诺就会完成。

用法:

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

代码:

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

自Node.js 8.5.0以来,我们有了新的< >强fs.copyFile < / >强< >强fs.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');
});

使用Node.js内置的复制函数

它提供了异步和同步版本:

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]) . copyFileSync(src, dest[, mode]

对于快速复制,您应该使用fs.constants.COPYFILE_FICLONE标志。它允许(对于支持此功能的文件系统)不实际复制文件的内容。只创建了一个新的文件条目,但它指向源文件的即写即拷“克隆”。

什么都不做/少做是做某事的最快方法;)

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

用承诺代替:

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"));
   const fs = require("fs");
fs.copyFileSync("filepath1", "filepath2"); //fs.copyFileSync("file1.txt", "file2.txt");

这是我个人用来复制一个文件和替换另一个文件使用Node.js:)

你可以很容易地使用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!");
}
});

<强>或< / >强

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


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

你可能想要使用async/await,因为node v10.0.0可以使用内置的fs Promises API

例子:

const fs = require('fs')


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

注意:

node v11.14.0, v10.17.0开始,API就不再是实验性的了。

更多信息:

承诺API

Promises copyFile

我写了一个小工具来测试不同的方法:

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

运行它

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

它使用child_process.exec()进行本地复制,使用fs进行复制文件。它使用creatererestream和各种不同的缓冲区大小(您可以通过在命令行上传递它们来更改缓冲区大小)。执行NPX copy-speed-test -h查看更多信息)。