โครงการที่ฉันกำลังทำงาน (node.js) แสดงถึงการดำเนินการจำนวนมากด้วยระบบไฟล์ (การคัดลอก / อ่าน / เขียน ฯลฯ ) ฉันต้องการทราบว่าวิธีใดเร็วที่สุดและฉันยินดีที่จะรับคำแนะนำ ขอบคุณ
โครงการที่ฉันกำลังทำงาน (node.js) แสดงถึงการดำเนินการจำนวนมากด้วยระบบไฟล์ (การคัดลอก / อ่าน / เขียน ฯลฯ ) ฉันต้องการทราบว่าวิธีใดเร็วที่สุดและฉันยินดีที่จะรับคำแนะนำ ขอบคุณ
คำตอบ:
นี่เป็นวิธีที่ดีในการคัดลอกไฟล์ในโค้ดหนึ่งบรรทัดโดยใช้สตรีม:
var fs = require('fs');
fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));
ในโหนด v8.5.0, copyFile ถูกเพิ่ม
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 เต็ม
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
จะ unpipe เท่านั้น คุณจะต้องโทรหา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()
จนถึงโหนด 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 syntax:
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
ใช้ . การโยนข้อยกเว้นเป็นที่นิยมกว่า
const fs = require("fs");
fs.copyFileSync("filepath1", "filepath2"); //fs.copyFileSync("file1.txt", "file2.txt");
นี่คือสิ่งที่ฉันใช้เพื่อคัดลอกไฟล์และแทนที่ไฟล์อื่นโดยใช้ node.js :)
สำหรับการคัดลอกที่รวดเร็วคุณควรใช้การfs.constants.COPYFILE_FICLONE
ตั้งค่าสถานะ อนุญาตให้ (สำหรับระบบไฟล์ที่สนับสนุนสิ่งนี้) ไม่คัดลอกเนื้อหาของไฟล์ มีเพียงรายการไฟล์ใหม่ที่ถูกสร้าง แต่จะชี้ไปที่Copy-on-Write "โคลน"ของไฟล์ต้นฉบับ
ที่จะไม่ทำอะไรเลย / น้อยลงเป็นวิธีที่เร็วที่สุดในการทำอะไรบางอย่าง;)
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?
มันให้ทั้งรุ่น async และ sync:
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) }
มิฉะนั้นจะมีความเสี่ยงในสถานการณ์ในกรณีที่แหล่งที่มาและเป้าหมายถูกแทนที่ด้วยความผิดพลาดข้อมูลของคุณจะหายไปอย่างถาวรโดยไม่สังเกตเห็นข้อผิดพลาดใด ๆ