jarivak
jarivak

Reputation: 858

How to increment the filename if file already exists in javascript

I have implemented Drag and Drop File Upload in my react project, so on every drag and drop of file into the drop zone , I'm taking the file and accessing it's name and it's data and converting the data to base64 using javscript's FileReader() and readAsDataURL() and updating the state, which I need to send it to bakend.

How to append a number to filename if the file with same name already exist in the state ?

eg: file(1).csv or file 2.csv

enter image description here

Main State

this.state : {
     Files:[],
}

Function that get's triggered every time for drag and drop of file

   FileHandling = (files) => {
    files.forEach((file) => {
      const reader = new FileReader();

      reader.readAsDataURL(file);
      reader.onload = () => {

        const CompleteData= {
          fileData: reader.result,
          fileName: file.name,
        };
         this.setState({
             Files:[...this.state.Files, CompleteData]
            })
      };
    });
  };

Upvotes: 3

Views: 5105

Answers (4)

Pessi S.
Pessi S.

Reputation: 83

Ok, It's not exactly in the format of the question, but it seems to me that it can help. Below is a simple js code, which goes through a list of strings representing file names, and computes the next name. If the file 'file.png' exists once - it will be returned 'file(1).png'. If the file 'file(1).png' also exists- it will be returned 'file(2).png', and etc.

let fileList=['fa.png','fb.mp4','fc.jpeg','fa(1).png'];

const getName=(fileName)=>{
  let [name,end]=fileName.split('.');
 let num = 0;
let curName = `${name}.${end}`;
let exists=fileList.filter(f => f === curName).length;
while(exists) {
  console.log('curName:',curName,'exists:',exists,'num:',num);
    curName = `${name}(${++num}).${end}`;
     exists=fileList.filter(f => f === curName).length;
  } 
  return curName;
}

console.log(getName('fa.png'));

see in codeSandbox

Upvotes: 1

Henri
Henri

Reputation: 801

You can check this.state.Files before. A recursive function could be used here. Imagine you load a file named export.csv. The second one would export.csv transformed in export_1.csv. But on a third one named export.csv, the verification would be done on export, leading to export_1 => Error ! The best is to do :

const checkNameOfTheFile = (newFileName) => {
    // Ex 'export.csv'
    const counter = this.state.Files.filter(f => f.fileName === newFileName).length;
    // If counter >= 2, an error has already been passed to the files because it means
    // 2 files have the same name
    if (counter >= 2) {
        throw 'Error duplicate name already present';
    }
    if (counter === 0) {
        return newFileName
    }
    if (counter === 1) {
        const newName = `${newFileName.split('.')[0]}_${counter}.${newFileName.split('.')[1]}`;
        // Return export_1.csv;
        return checkNameOfTheFile(newName);
        // We need to check if export_1.csv has not been already taken.
        // If so, the new name would be export_1_1.csv, not really pretty but it can be changed easily in this function
    }
};


const CompleteData= {
    fileData: reader.result,
    fileName: checkNameOfTheFile(file.name),
};

Upvotes: 2

Zibx
Zibx

Reputation: 94

Make any pattern that you want on the line with a comment.

 const getUniqueName = (fileName, index = 0) => {
   let checkName = fileName, ext = '';
   if(index){
     if(checkName.indexOf('.') > -1){
       let tokens = checkName.split('.'); ext = '.' + tokens.pop();
       checkName = tokens.join('.');
     }

     // make any pattern here
     checkName = `${checkName} (${index})${ext}`; 
   }
   
   const nameExists = this.state.Files.filter(f=>f.fileName === checkName).length > 0;
   return nameExists ? getUniqueName(fileName, index + 1) : checkName;
 }

 FileHandling = (files) => {
    files.forEach((file) => {
      const reader = new FileReader();

      reader.readAsDataURL(file);
      reader.onload = () => {
        const CompleteData = {
          fileData: reader.result,
          fileName: getUniqueName(file.name),
        };
         this.setState({
             Files:[...this.state.Files, CompleteData]
            })
      };
    });
  };

Upvotes: 4

James L.
James L.

Reputation: 14515

Determine if there is a matching file, if so determine if it is already a duplicate (has a number at the end already). If so find its number and increment it. Otherwise just append a '1'. If there are no matching files, don't do anything.

FileHandling = (files) => {
files.forEach((file) => {
  const reader = new FileReader();

  reader.readAsDataURL(file);
  reader.onload = () => {
    let existingFiles = this.state.Files.filter(x=>x.fileName==file.Name);
    let fileName = file.Name;
    if(existingFiles.length > 0) {
      let oldFileName = existingFiles[0].split('.')[0];
      let oldFileMatchNumberMatch = oldFileName.match(/\d+$/);
      let fileNumber = (oldFileMatchNumberMatch) parseInt(oldFileMatchNumberMatch[0], 10) : 1;
      fileName = file.Name + fileNumber; //if file.Name has an extension, you'll need to split, add the number to the end of the 0'th element, and rejoin it
    }

    const CompleteData= {
      fileData: reader.result,
      fileName: file.name,
    };
     this.setState({
         Files:[...this.state.Files, CompleteData]
        })
  };
});

Upvotes: 2

Related Questions