How to Generate unique file names in C#

后端 未结 19 2319
生来不讨喜
生来不讨喜 2020-12-02 05:43

I have implemented an algorithm that will generate unique names for files that will save on hard drive. I\'m appending DateTime: Hours,Minutes,Second an

相关标签:
19条回答
  • 2020-12-02 06:09

    You can have a unique file name automatically generated for you without any custom methods. Just use the following with the StorageFolder Class or the StorageFile Class. The key here is: CreationCollisionOption.GenerateUniqueName and NameCollisionOption.GenerateUniqueName

    To create a new file with a unique filename:

    var myFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("myfile.txt", NameCollisionOption.GenerateUniqueName);
    

    To copy a file to a location with a unique filename:

    var myFile2 = await myFile1.CopyAsync(ApplicationData.Current.LocalFolder, myFile1.Name, NameCollisionOption.GenerateUniqueName);
    

    To move a file with a unique filename in the destination location:

    await myFile.MoveAsync(ApplicationData.Current.LocalFolder, myFile.Name, NameCollisionOption.GenerateUniqueName);
    

    To rename a file with a unique filename in the destination location:

    await myFile.RenameAsync(myFile.Name, NameCollisionOption.GenerateUniqueName);
    
    0 讨论(0)
  • 2020-12-02 06:09

    I usually do something along these lines:

    • start with a stem file name (work.dat1 for instance)
    • try to create it with CreateNew
    • if that works, you've got the file, otherwise...
    • mix the current date/time into the filename (work.2011-01-15T112357.dat for instance)
    • try to create the file
    • if that worked, you've got the file, otherwise...
    • Mix a monotonic counter into the filename (work.2011-01-15T112357.0001.dat for instance. (I dislike GUIDs. I prefer order/predictability.)
    • try to create the file. Keep ticking up the counter and retrying until a file gets created for you.

    Here's a sample class:

    static class DirectoryInfoHelpers
    {
        public static FileStream CreateFileWithUniqueName( this DirectoryInfo dir , string rootName )
        {
            FileStream fs = dir.TryCreateFile( rootName ) ; // try the simple name first
    
            // if that didn't work, try mixing in the date/time
            if ( fs == null )
            {
                string date = DateTime.Now.ToString( "yyyy-MM-ddTHHmmss" ) ;
                string stem = Path.GetFileNameWithoutExtension(rootName) ;
                string ext  = Path.GetExtension(rootName) ?? ".dat" ;
    
                ext = ext.Substring(1);
    
                string fn = string.Format( "{0}.{1}.{2}" , stem , date , ext ) ;
                fs = dir.TryCreateFile( fn ) ;
    
                // if mixing in the date/time didn't work, try a sequential search
                if ( fs == null )
                {
                    int seq = 0 ;
                    do
                    {
                        fn = string.Format( "{0}.{1}.{2:0000}.{3}" , stem , date , ++seq , ext ) ;
                        fs = dir.TryCreateFile( fn ) ;
                    } while ( fs == null ) ;
                }
    
            }
    
            return fs ;
        }
    
        private static FileStream TryCreateFile(this DirectoryInfo dir , string fileName )
        {
            FileStream fs = null ;
            try
            {
                string fqn = Path.Combine( dir.FullName , fileName ) ;
    
                fs = new FileStream( fqn , FileMode.CreateNew , FileAccess.ReadWrite , FileShare.None ) ;
            }
            catch ( Exception )
            {
                fs = null ;
            }
            return fs ;
        }
    
    }
    

    You might want to tweak the algorithm (always use all the possible components to the file name for instance). Depends on the context -- If I was creating log files for instance, that I might want to rotate out of existence, you'd want them all to share the same pattern to the name.

    The code isn't perfect (no checks on the data passed in for instance). And the algorithm's not perfect (if you fill up the hard drive or encounter permissions, actual I/O errors or other file system errors, for instance, this will hang, as it stands, in an infinite loop).

    0 讨论(0)
  • 2020-12-02 06:14
    System.IO.Path.GetRandomFileName()
    

    Path.GetRandomFileName() on MSDN.

    0 讨论(0)
  • 2020-12-02 06:15

    Here's an algorithm that returns a unique readable filename based on the original supplied. If the original file exists, it incrementally tries to append an index to the filename until it finds one that doesn't exist. It reads the existing filenames into a HashSet to check for collisions so it's pretty quick (a few hundred filenames per second on my machine), it's thread safe too, and doesn't suffer from race conditions.

    For example, if you pass it test.txt, it will attempt to create files in this order:

    test.txt
    test (2).txt
    test (3).txt
    

    etc. You can specify the maximum attempts or just leave it at the default.

    Here's a complete example:

    class Program
    {
        static FileStream CreateFileWithUniqueName(string folder, string fileName, 
            int maxAttempts = 1024)
        {
            // get filename base and extension
            var fileBase = Path.GetFileNameWithoutExtension(fileName);
            var ext = Path.GetExtension(fileName);
            // build hash set of filenames for performance
            var files = new HashSet<string>(Directory.GetFiles(folder));
    
            for (var index = 0; index < maxAttempts; index++)
            {
                // first try with the original filename, else try incrementally adding an index
                var name = (index == 0)
                    ? fileName
                    : String.Format("{0} ({1}){2}", fileBase, index, ext);
    
                // check if exists
                var fullPath = Path.Combine(folder, name);
                if(files.Contains(fullPath))
                    continue;
    
                // try to create the file
                try
                {
                    return new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write);
                }
                catch (DirectoryNotFoundException) { throw; }
                catch (DriveNotFoundException) { throw; }
                catch (IOException) 
                {
                    // Will occur if another thread created a file with this 
                    // name since we created the HashSet. Ignore this and just
                    // try with the next filename.
                } 
            }
    
            throw new Exception("Could not create unique filename in " + maxAttempts + " attempts");
        }
    
        static void Main(string[] args)
        {
            for (var i = 0; i < 500; i++)
            {
                using (var stream = CreateFileWithUniqueName(@"c:\temp\", "test.txt"))
                {
                    Console.WriteLine("Created \"" + stream.Name + "\"");
                }
            }
    
            Console.ReadKey();
        }
    }
    
    0 讨论(0)
  • 2020-12-02 06:15

    I've written a simple recursive function that generates file names like Windows does, by appending a sequence number prior to the file extension.

    Given a desired file path of C:\MyDir\MyFile.txt, and the file already exists, it returns a final file path of C:\MyDir\MyFile_1.txt.

    It is called like this:

    var desiredPath = @"C:\MyDir\MyFile.txt";
    var finalPath = UniqueFileName(desiredPath);
    
    private static string UniqueFileName(string path, int count = 0)
    {
        if (count == 0)
        {
            if (!File.Exists(path))
            {
                return path;
            }
        }
        else
        {
            var candidatePath = string.Format(
                @"{0}\{1}_{2}{3}",
                Path.GetDirectoryName(path),
                Path.GetFileNameWithoutExtension(path),
                count,
                Path.GetExtension(path));
    
            if (!File.Exists(candidatePath))
            {
                return candidatePath;
            }
        }
    
        count++;
        return UniqueFileName(path, count);
    }
    
    0 讨论(0)
  • 2020-12-02 06:16

    Use

    Path.GetTempFileName()
    

    or use new GUID().

    Path.GetTempFilename() on MSDN.

    0 讨论(0)
提交回复
热议问题