Проект, над яким я працюю (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не є портативним у Window, всупереч повному рішенню 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заповіті лише відколює її. Вам би довелося зателефонувати 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 / wait:
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/isissue/25375
Ну, зазвичай добре уникати асинхронних файлових операцій. Ось короткий приклад синхронізації (тобто відсутність обробки помилок):
var fs = require('fs');
fs.writeFileSync(targetFile, fs.readFileSync(sourceFile));
*Syncметодів повністю проти філософії nodejs! Я також думаю, що вони повільно застаріли. Вся ідея nodejs полягає в тому, що це один потік і керований подіями.
Рішення Майка Шиллінга з вирішенням помилок із скороченням для обробника подій помилки.
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прапор. Це дозволяє (для файлових систем, що підтримують це) насправді не копіювати вміст файлу. Просто створюється новий запис файлу, але він вказує на "клон" копіювання на запис "вихідний файл".
Не робити нічого / менш - це найшвидший спосіб зробити щось;)
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) }
інакше існує ризик у сценарії, якщо джерело та ціль помилково замінені, ваші дані будуть назавжди втрачені, не помічаючи жодної помилки.