我正在处理的项目(node.js)包含文件系统的大量操作(复制/读取/写入等)。我想知道哪些方法是最快的,我很乐意得到建议。谢谢。
我正在处理的项目(node.js)包含文件系统的大量操作(复制/读取/写入等)。我想知道哪些方法是最快的,我很乐意得到建议。谢谢。
Answers:
这是使用流在一行代码中复制文件的好方法:
var fs = require('fs');
fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));
const fs = require('fs');
// 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');
});
createReadStream
和并检查是否有createWriteStream
错误,因此您将不会得到一线希望(尽管它仍然会如此之快)。
cp test.log newLog.log
通过require('child_process').exec
?
copy
,与完整的Node.js解决方案相反,它不是在Windows上可移植的。
child_process.execFile('/bin/cp', ['--no-target-directory', source, target])
。
fs.createReadStream('./init/xxx.json').pipe(fs.createWriteStream('xxx.json'));
相同的机制,但这增加了错误处理:
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;
}
}
}
WriteStream
遗嘱中的错误只会解开它。您必须打电话给rd.destroy()
自己。至少那是发生在我身上的事情。遗憾的是,除了源代码外,没有多少文档。
cb
?作为第三个论点我们应该传递什么?
createReadStream/createWriteStream
由于某种原因,我无法使该方法正常工作,但是使用fs-extra
npm模块,它可以立即工作。我不确定性能是否有所不同。
npm install --save fs-extra
var fs = require('fs-extra');
fs.copySync(path.resolve(__dirname,'./init/xxx.json'), 'xxx.json');
fs.copy(src, dst, callback);
,这些应解决@mvillar的问题。
从Node.js 8.5.0开始,我们有了新的fs.copyFile和fs.copyFileSync方法。
用法示例:
var fs = require('fs');
// 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');
});
copyFile()
在覆盖更长的文件时会出现错误。由uv_fs_copyfile()
直到Node v8.7.0(libuv 1.15.0)提供。参见github.com/libuv/libuv/pull/1552
快速编写,使用方便,具有承诺和错误管理功能。
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;
}
}
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);});
并查看了相关规范,您就是对的:尝试解决或拒绝已解决的承诺没有任何效果。也许您可以扩展答案并解释为什么要用这种方式编写函数?谢谢:-)
close
应该finish
用于可写流。
/dev/stdin
,那就是一个错误github.com/joyent/node/issues/25375
好吧,通常最好避免异步文件操作。这是简短的(即无错误处理)同步示例:
var fs = require('fs');
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
*Sync
方法完全违反了nodejs的理念!我还认为它们正在逐渐被弃用。nodejs的整体思想是它是单线程的并且是事件驱动的。
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;
}
}
}
如果您不关心它是异步的,并且不复制千兆字节大小的文件,并且不想只为一个函数添加另一个依赖项:
function copySync(src, dest) {
var data = fs.readFileSync(src);
fs.writeFileSync(dest, data);
}
fs.existsSync
呼叫应省略。该文件可能会在fs.existsSync
通话和fs.readFileSync
通话之间消失,这意味着fs.existsSync
通话无法保护我们免受任何伤害。
false
如果fs.existsSync
失败则返回很可能是不良的人体工程学设计,因为很少有消费者copySync
会认为每次调用返回值时都要手动检查返回值,这比我们fs.writeFileSync
等人所做的更多。。实际上最好抛出一个异常。
对于快速复制,应使用该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"));
fs.promises.copyFile
benweet的解决方案在复制之前检查文件的可见性:
function copy(from, to) {
return new Promise(function (resolve, reject) {
fs.access(from, fs.F_OK, function (error) {
if (error) {
reject(error);
} else {
var inputStream = fs.createReadStream(from);
var outputStream = fs.createWriteStream(to);
function rejectCleanup(error) {
inputStream.destroy();
outputStream.end();
reject(error);
}
inputStream.on('error', rejectCleanup);
outputStream.on('error', rejectCleanup);
outputStream.on('finish', resolve);
inputStream.pipe(outputStream);
}
});
});
}
为什么不使用内置复制功能的nodejs?
它提供了异步和同步版本:
const fs = require('fs');
// 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');
});
https://nodejs.org/api/fs.html#fs_fs_copyfilesync_src_dest_flags
迈克的解决方案,但有希望:
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);
});
};
改善另一个答案。
特征:
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);
}
上述所有不检查源文件是否存在的解决方案都是危险的...例如
fs.stat(source, function(err,stat) { if (err) { reject(err) }
否则,如果错误地替换了源和目标,则存在场景风险,您的数据将永久丢失而不会注意到任何错误。