tags:

views:

59

answers:

4

How do you move a file after generating it to another folder without having name collision problem?

for example, i generate a CSV file name foo_20090820.csv and if i run the program again later on 08/20/2009 then the file will be foo_20090820.csv since on my target folder there already an file generated before the second file. The program will run into an error.

I tried looking into the target folder for the same file name and add some random number in front the second file but it didn't work quite well.

any idea?

+4  A: 

Here is pseudo code of how I handle this:

newName = "foo_20090820.csv"
i = 1
while file exists newName
    newName = "foo_20090820-" + i.ToString() + ".csv
    i++
While Loop
Move oldFile to newName
EBGreen
This is the best way to handle it. The only other way would be if you just want to use the latest version there is a function on File called Exist that will tell you if a file exists or not and if it does you can delete the old one.
David Basarab
In your example, you are not incrementing the loop counter.
Steve Guidi
Oops...I should have said Pseudo-Functional code. I will fix it. Thanks.
EBGreen
This does not guarantee no collisions as there is a race condition between the check and the move.
JP Alioto
That is true if the possibility of multiple processes/threads trying to do this at the same time exists. That possibility did not seem to exist from the way I read the question.
EBGreen
+1  A: 

Another idea would be to encode the time in the file name. I already see you have the date encoded; what I'm suggesting is tacking on the time.

So you'd end up with something like this:

foo_yyyyMMdd_HHmmss (plus .csv of course)

which would add hours (24 hour clock format), minutes and seconds to your name.

Note that not only would you be able to sort these files in the order they were moved, but their filenames would tell you when they were moved.

Jay Riggs
+2  A: 

If you want absolutely no chance of a collision, you could tack on a GUID.

JP Alioto
A: 

Here is an improvement to EBGreen's solution, which avoids the race condition between checking for the existence of and creating the file.

bool SafeMove(string sourceFilename, string destFilename)
{
    for (int i = 0; i < RetryThreshold; ++i)
    {
        try
        {
            File.Move(sourceFilename, destFilename);
            return true;
        }
        catch(IOException)
        {
            destFilename =
                Path.GetFilenameWithoutExtension(destFilename) + i.ToString() +
                Path.GetExtension(destFilename);
        }
    }

    return false;
}

There are some problems with this code, but it demonstrates the attempt to retry after the Move() operation fails. You should definitely perform some smarter exception handling since not all IOExceptions imply a reason for retrying. Also, returning false is not wise since we lose the error context.

Alternatively, if you're not concerned with the readability of directory or filename, use JP's solution of appending a Guid to filename.

Steve Guidi
While it would still be functional, this code would produce file names like foo1.csv, foo12.csv, foo123.csv. As I say, this would be functional, but if being able to look at the file and make quick decisions based on write order is important, you should stick the original base name into a var and append to that.
EBGreen