1

I am using copy method of fs-extra to copy files from a source to destination. My use case is to create a copy of the file with a name like if a file of the same name exists in the destination. The copy method of fs-extra module overwrites the destination file.

Ravi Kukreja
  • 627
  • 1
  • 8
  • 17

2 Answers2

2

You could try something like this:

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

async function copy(src, dest) {
  try {
    await fs.copy(src, dest, { overwrite: false, errorOnExist: true });
    return true;
  } catch (error) {
    if (error.message.includes('already exists')) {
      return false;
    }
    throw error;
  }
}

async function copyWithoutOverwrite(src, dest, maxAttempts) {    
  try {
    if (!await copy(src, dest)); {
      for (let i = 1; i <= maxAttempts; i++) {
        if (await copy(src, `${dest}_copy${i}`)) {
          return;
        }
      }
    }
  } catch (error) {
    console.error(error);
  }
}

const src = '/tmp/testfile';
const dest = '/tmp/mynewfile';
const maxAttempts = 10;

copyWithoutOverwrite(src, dest, maxAttempts);
nijm
  • 2,158
  • 12
  • 28
  • Also see overwrite property in the documentation :-) https://github.com/jprichardson/node-fs-extra/blob/master/docs/copy-sync.md – ow3n Feb 08 '22 at 00:32
1

So basically you need to implement custom copy procedure, that you can interrupt and alter at any moment. fs-jetpack does this very well.

const pathUtil = require("path");
const jetpack = require("fs-jetpack");

const src = jetpack.cwd("path/to/source/folder");
const dst = jetpack.cwd("path/to/destination/folder");

const findUnusedPath = path => {
  const pathDir = pathUtil.dirname(path);
  const extension = pathUtil.extname(path);
  const fileName = pathUtil.basename(path, extension);
  const pathCandidate = pathUtil.join(pathDir, `${fileName}-duplicate${extension}`);

  if (dst.exists(pathCandidate)) {
    // Will just add "-duplicate-duplicate-duplicate..." to name 
    // of the file until finds unused name.
    return findUnusedPath(pathCandidate);
  } else {
    return pathCandidate;
  }
};

// Iterate over all files in source directory and manually decide 
// where to put them in destination directory.
src.find().forEach(filePath => {
  const content = src.read(filePath, "buffer");
  let destPath = filePath;
  if (dst.exists(destPath)) {
    destPath = findUnusedPath(destPath);
  }
  dst.write(destPath, content);
});

Here using file read/write instead of copy, because it's faster in this particular case. Copy needs to check first what the path is: directory or file. If we already know it is a file there is no need for this extra work.