Проект, над которым я работаю (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()
Till 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 заключается в том, что он однопоточный и управляемый событиями.
Решение Майка Шиллинга с обработкой ошибок с ярлыком для обработчика событий ошибок.
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
et al. , Бросать исключение на самом деле предпочтительнее.
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, встроенный в функцию копирования?
Он предоставляет как асинхронную, так и синхронизированную версию:
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) }
в противном случае в сценарии существует риск, если источник и цель по ошибке будут заменены, ваши данные будут навсегда потеряны без замечания какой-либо ошибки.