Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: How would you make a unique filename by adding a number?

I would like to create a method which takes either a filename as a string or a FileInfo and adds an incremented number to the filename if the file exists. But can't quite wrap my head around how to do this in a good way.

For example, if I have this FileInfo

var file = new FileInfo(@"C:\file.ext"); 

I would like the method to give me a new FileInfo with C:\file 1.ext if C:\file.ext existed, and C:\file 2.ext if C:\file 1.ext existed and so on. Something like this:

public FileInfo MakeUnique(FileInfo fileInfo) {     if(fileInfo == null)         throw new ArgumentNullException("fileInfo");     if(!fileInfo.Exists)         return fileInfo;      // Somehow construct new filename from the one we have, test it,      // then do it again if necessary. } 
like image 425
Svish Avatar asked Jul 03 '09 06:07

Svish


2 Answers

public FileInfo MakeUnique(string path) {                 string dir = Path.GetDirectoryName(path);     string fileName = Path.GetFileNameWithoutExtension(path);     string fileExt = Path.GetExtension(path);      for (int i = 1; ;++i) {         if (!File.Exists(path))             return new FileInfo(path);          path = Path.Combine(dir, fileName + " " + i + fileExt);     } } 

Obviously, this is vulnerable to race conditions as noted in other answers.

like image 170
mmx Avatar answered Oct 16 '22 09:10

mmx


Lots of good advice here. I ended up using a method written by Marc in an answer to a different question. Reformatted it a tiny bit and added another method to make it a bit easier to use "from the outside". Here is the result:

private static string numberPattern = " ({0})";  public static string NextAvailableFilename(string path) {     // Short-cut if already available     if (!File.Exists(path))         return path;      // If path has extension then insert the number pattern just before the extension and return next filename     if (Path.HasExtension(path))         return GetNextFilename(path.Insert(path.LastIndexOf(Path.GetExtension(path)), numberPattern));      // Otherwise just append the pattern to the path and return next filename     return GetNextFilename(path + numberPattern); }  private static string GetNextFilename(string pattern) {     string tmp = string.Format(pattern, 1);     if (tmp == pattern)         throw new ArgumentException("The pattern must include an index place-holder", "pattern");      if (!File.Exists(tmp))         return tmp; // short-circuit if no matches      int min = 1, max = 2; // min is inclusive, max is exclusive/untested      while (File.Exists(string.Format(pattern, max)))     {         min = max;         max *= 2;     }      while (max != min + 1)     {         int pivot = (max + min) / 2;         if (File.Exists(string.Format(pattern, pivot)))             min = pivot;         else             max = pivot;     }      return string.Format(pattern, max); } 

Only partially tested it so far, but will update if I find any bugs with it. (Marcs code works nicely!) If you find any problems with it, please comment or edit or something :)

like image 35
4 revs, 4 users 72% Avatar answered Oct 16 '22 11:10

4 revs, 4 users 72%