Apostrofix
Apostrofix

Reputation: 2180

FileInfo.MoveTo if file exists - rename

I have an application that moves files from one directory to another, but sometimes a conflict occurs and the file already exists in the destination directory.

When that happens, I want to move the file with a different name - e.g. if the file is named test.txt, I want to name it test.txt.1. That's okay, but how do I do it next time, if the file is again test.txt, but in the destination folder we have both test.txt and test.txt.1.

My problem is that I can't find the last created file so that I can read its index and increment it with 1. Any suggestions?

string sourcePath = "C:\\Files\\test.txt";
string filename = Path.GetFileName(sourcePath);
string pathTo = "C:\\Files\\test\\" + filename;

try
{
    var fileInfo = new FileInfo(sourcePath);
    fileInfo.MoveTo(pathTo);
}
catch (IOException ex)
{
    var fileInfo = new FileInfo(sourcePath);
    var file = Directory.GetFiles(pathTo, filename+".1").FirstOrDefault();
    if (file == null)
    {
        fileInfo.MoveTo(pathTo+".1");
    }
    else
    {
        //find the old file, read it's last index and increment it with 1
    }

}

Upvotes: 2

Views: 10210

Answers (4)

Alexander Manekovskiy
Alexander Manekovskiy

Reputation: 3203

I would prefer to write a method that will return a next index for a file and remove try-catch block:

string sourcePath = "C:\\Files\\test.txt";
string filename = Path.GetFileName(sourcePath);
string pathTo = "C:\\Files\\test\\"; // the destination file name would be appended later

var fileInfo = new FileInfo(sourcePath);
if (!fileInfo.Exists)
{
    fileInfo.MoveTo(pathTo);
}
else
{
    // Get all files by mask "test.txt.*"
    var files = Directory.GetFiles(pathTo, string.Format("{0}.*", filename)).ToArray();
    var newExtension = GetNewFileExtension(files); // will return .1, .2, ... .N

    fileInfo.MoveTo(Path.Combine(pathTo, string.Format("{0}{1}", filename, newExtension)));
}

And the new method for getting the new index:

public static string GetNewFileExtension(string[] fileNames) 
{
    int maxIndex = 0;

    foreach (var fileName in fileNames)
    {
        // get the file extension and remove the "."
        string extension = Path.GetExtension(fileName).Substring(1); 
        int parsedIndex;
        // try to parse the file index and do a one pass max element search
        if(int.TryParse(extension, out parsedIndex)) 
        {
            if(parsedIndex > maxIndex)
            {
                maxIndex = parsedIndex;
            }
        }
    }

    // increment max index by 1
    return string.Format(".{0}", maxIndex + 1); 
}

Upvotes: 2

Matthijs
Matthijs

Reputation: 3170

I have rewritten your code a little because you were programming against the exception, which is something I really do not encourage.

First, it checks if the original file already exists.

Then, as your original code, it tries to create the file with a .1 indexer. If that is already present, it goes through the directory to locate all files that have the same filename.

Last, it goes to find the last index used and increments it by one.

Note that you could also skip the first if-statement in the else-statement because it will still search for the last index used; and if none is present, the lastIndex will stay 0 (with one increment so it will use 1 as index for the new file).

var fileInfo = new FileInfo(sourcePath);

// Check if the file already exists.
if (!fileInfo.Exists)
    fileInfo.MoveTo(pathTo);
else
{
    var file = Directory.GetFiles(pathTo, filename + ".1").FirstOrDefault();
    if (file == null)
    {
        fileInfo.MoveTo(pathTo + ".1");
    }
    else
    {
        // Get all files with the same name.
        string[] getSourceFileNames = Directory.GetFiles(Path.GetDirectoryName(pathTo)).Where(s => s.Contains(filename)).ToArray();

        // Retrieve the last index.
        int lastIndex = 0;
        foreach (string s in getSourceFileNames)
        {
            int currentIndex = 0;
            int.TryParse(s.Split('.').LastOrDefault(), out currentIndex);
            if (currentIndex > lastIndex)
                lastIndex = currentIndex;
        }

        // Do something with the last index.
        lastIndex++;
        fileInfo.MoveTo(pathTo + lastIndex);
    }
}

Upvotes: 2

Tomas Kubes
Tomas Kubes

Reputation: 25108

Func<int, string> getFileName= delegate(int i) 
{
    return string.Format("{0}/{1}{2}.{3}", dir, filenameWithouExt, i, ext);
};

int i = 0;
while(File.Exists(getFileName(i)))
{
 i++;
}
fileInfo.MoveTo(getFileName(i));

It depends how much files do you have. You can make it more quicker if you have a lot of files:

int i = 0;
while(File.Exists(getFileName(i)))
{
  i+=100;
}
i-=90;

while(File.Exists(getFileName(i)))
{
  i+=10;
}
i-=9;

while(File.Exists(getFileName(i)))
{
  i+=1;
}

Upvotes: 2

Naren
Naren

Reputation: 2311

You can use a function like this..

void MoveFileToPath(string sourceFilePath,string destinationDirectory)
    {
        int index = 1;
        string fileName = Path.GetFileName(sourceFilePath);
        string destPath = destinationDirectory+fileName;

        while(File.Exists(destPath))
        {
            destPath = string.Format("{0}{1}.{2}",destinationDirectory,fileName,index);
            index++;
        }
        var fileInfo = new FileInfo(sourceFilePath);
        Console.WriteLine("Test:"+destPath);
        fileInfo.MoveTo(destPath);
    }

Upvotes: 4

Related Questions