Самый быстрый способ скопировать файл в node.js

Проект, над которым я работаю (node.js), подразумевает много операций с файловой системой (копирование/чтение/запись и т.д.). Я хотел бы знать, какие методы самые быстрые, и я буду рад за некоторые советы.

Ответ 1

Это хороший способ скопировать файл в одну строку кода, используя потоки:

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

Ответ 2

Тот же механизм, но это добавляет обработку ошибок:

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

Ответ 3

Мне почему-то не удалось получить метод createReadStream/createWriteStream, но с помощью модуля fs-extra npm он работал сразу. Однако я не уверен в различиях в производительности.

fs-extra

npm install --save fs-extra

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

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

Ответ 4

Так как 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');
});

Ответ 5

Быстро написать и удобно использовать, с обещаниями и управлением ошибками.

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

Ответ 6

Хорошо, обычно бывает полезно избегать асинхронных операций с файлами. Вот пример синхронизации (например, отсутствие обработки ошибок):

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

Ответ 7

Решение Майка Шиллинга с обработкой ошибок с кратким сокращением для обработчика событий ошибки.

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

Ответ 8

Если вам неинтересно, что они являются асинхронными и не копируют файлы размером с гигабайт, и не будут добавлять другую зависимость только для одной функции:

function copySync(src, dest) {
  if (!fs.existsSync(src)) {
    return false;
  }

  var data = fs.readFileSync(src, 'utf-8');
  fs.writeFileSync(dest, data);
}

Ответ 9

решение 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);
            }
        });
    });
}

Ответ 10

Mike solution, но с promises:

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

Ответ 11

Улучшение другого ответа.

Особенности:

  • Если папка 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);
}

Ответ 12

все вышеперечисленные решения, которые не проверяют существование исходного файла, опасны... например.

fs.stat(source, function(err,stat) { if (err) { reject(err) }

В противном случае существует риск в сценарии в случае, если источник и цель заменены ошибкой, ваши данные будут потеряны без потери какой-либо ошибки.

Ответ 13

Почему бы не использовать 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

Ответ 14

Для быстрых копий вы должны использовать флаг 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"));