FileUpload – if file name exist concat a number between parentheses at the end of name

I want to upload file (one at a time) to a folder:

GetUniqueName function (mentioned below) will return a unique file name

This is the code I use to do it:

public static string GetUniqueName(string fileName)
{
        string dir = Globals.Directories.GetCustomCategoryThumbnailDir();
        string fileExtension = Path.GetExtension(fileName);
        string fileNameWE = Path.GetFileNameWithoutExtension(fileName);
        string[] files = Directory.GetFiles(dir, "*" + fileExtension)
                                .Select(Path.GetFileName)
                                .ToArray();
        string uniqueName = fileNameWE;
        int nextNum = 0;
        bool fileExist = false;
        string pattern = @"(.*)\(([\d]+)\)";

        foreach (var file in files)
        {
            var tempFileName = Path.GetFileNameWithoutExtension(file);
            var match = Regex.Match(tempFileName, pattern);

            if (tempFileName.Equals(fileNameWE))
            {
                // file exist in folder
                fileExist = true;
            }
            if (tempFileName.StartsWith(fileNameWE) && match.Success)
            {
                // there is a file name that start with "fileToUpload" name, we want to to take the number
                nextNum = Convert.ToInt32(match.Groups[2].Value);
                nextNum++;
            }
        }

        if (nextNum == 0 && !fileExist)
        {
            // filename dont exist                
            return fileNameWE + fileExtension;
        }
        if (nextNum == 0 && fileExist) 
        {
            // the file name exist without (1)
            fileNameWE = $"{fileNameWE}(1)";
            return fileNameWE + fileExtension;
        }
        else
        {
            var haveParentheses = Regex.Match(fileNameWE, pattern);

            if (haveParentheses.Success)
            {
                // we need to reset the nextNum
                nextNum = 1; 
            }

            // return the new unique name with suffix
            fileNameWE = string.Format("{0}({1})", fileNameWE, nextNum);
            return fileNameWE + fileExtension;
        }
}
  • All the solution that i find online are keeping the file name unique with the use of GUID or DateTime
  • for other cases that i checked the function work correctly and will return a “good” file name.

Some examples:

  • The folder contain:
    • army.png

I want to upload: army.png

  • The folder will contain:
    • army.png
    • army(1).png

I want to upload again: army.png

  • The folder will contain:
    • army.png
    • army(1).png
    • army(2).png

I want to upload : army(2).png

  • The folder will contain:
    • army.png
    • army(1).png
    • army(2).png
    • army(2)(1).png

I want to upload again: army(2).png

  • The folder will contain:
    • army.png
    • army(1).png
    • army(2).png
    • army(2)(1).png
    • army(2)(2).png

I want to upload again: army(2).png

  • The folder will contain:
    • army.png
    • army(1).png
    • army(2).png
    • army(2)(1).png
    • army(2)(2).png
    • army(2)(3).png

I want to upload : army(2)(2).png

  • The folder will contain:
    • army.png
    • army(1).png
    • army(2).png
    • army(2)(1).png
    • army(2)(2).png
    • army(2)(3).png
    • army(2)(2)(1).png

How can I fix the function so it will return the correct string?

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

Final version

This is tested and working according to all the cases on the question:

public static string GetUniqueName(string fileName)
{
    string dir = @"C:\Users\support\Desktop\Zohar\SO\Upload\Target";
    var targetPath = Path.Combine(dir, fileName);
    string fileExtension = Path.GetExtension(targetPath);
    string fileNameWE = Path.GetFileNameWithoutExtension(targetPath);
    int i = 1;
    while (File.Exists(targetPath))
    {
        fileName = string.Format("{0}({1}){2}", fileNameWE, i, fileExtension);
        targetPath = Path.Combine(dir, fileName);
        i++;
    }
    return targetPath;
}

Solution 2

Ok, unfortunately I couldn’t found the problem in your poster algorithm, but I wrote a new one, and I tested with several names. Appears to be working out. Please check-it:

public static string GetUniqueName(string fileName)
{
    var dir = Globals.Directories.GetCustomCategoryThumbnailDir();

    var fileExtension = Path.GetExtension(fileName);
    var fileNameWE = Path.GetFileNameWithoutExtension(fileName);
    var files = Directory.GetFiles(dir, "*" + fileExtension)
        .Select(Path.GetFileName)
        .Where(w => w.StartsWith(fileNameWE)) // included condition.
        .ToArray();

    if (!files.Any()) return fileName;

    var pattern = fileNameWE
        .Select(s => "[" + s + "]")
        .Aggregate("", (ac, i) => ac + i);

    var regex = new Regex(pattern + @"[(](?<counter>\d)[)]");

    var previous = files
        .Select(file => regex.Match(file))
        .Where(match => match.Success)
        .OrderByDescending(match => int.Parse(match.Groups["counter"].Value))
        .FirstOrDefault();

    var correctIndex = previous != null
        ? int.Parse(previous.Groups["counter"].Value) + 1
        : 1;

    return fileNameWE + "(" + correctIndex + ")" + fileExtension;
}

TEST Scenarios:

army(2).png -> army(2)(2).png
army.png -> army(3).png
army(1).png -> army(1)(1).png

Solution 3

Sounds like you should just run a loop, right?

var fileName = fileNameWE + fileExtension;

while(File.Exists(Path.Combine(dir, fileName)))
{
  fileNameWE += "(1)";
  fileName = fileNameWE + fileExtension;
} 

return fileName;

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply