如何在C#中生成唯一的文件名

Fra*_*dal 125 c#

我已经实现了一种算法,该算法将为将保存在硬盘驱动器上的文件生成唯一的名称.我附加DateTime:小时,分钟,秒和毫秒,但它仍然会生成重复的文件名,因为我一次上传多个文件.

为存储在硬盘驱动器上的文件生成唯一名称的最佳解决方案是什么,因此没有2个文件相同?

Uwe*_*eim 228

如果可读性无关紧要,请使用GUID.

例如:

var myUniqueFileName = string.Format(@"{0}.txt", Guid.NewGuid());
Run Code Online (Sandbox Code Playgroud)

或者更短:

var myUniqueFileName = $@"{Guid.NewGuid()}.txt";
Run Code Online (Sandbox Code Playgroud)

在我的程序中,我有时会尝试10次生成可读的名称("Image1.png".."Image10.png"),如果失败(因为文件已经存在),我会回到GUID.

更新:

最近,我还使用DateTime.Now.Ticks了GUID代替GUID:

var myUniqueFileName = string.Format(@"{0}.txt", DateTime.Now.Ticks);
Run Code Online (Sandbox Code Playgroud)

要么

var myUniqueFileName = $@"{DateTime.Now.Ticks}.txt";
Run Code Online (Sandbox Code Playgroud)

对我来说,好处是,与GUID相比,这会生成更短,更"漂亮"的文件名.

请注意,在某些情况下(例如,在很短的时间内生成大量随机名称),这可能会产生非唯一值.

如果您想确保文件名是唯一的,即使将它们传输到其他计算机,也要坚持使用GUID.

  • 我喜欢使用Ticks作为GUID真的很难看.您还可以获取Ticks的哈希值,这会减少文件名的字符长度.`DateTime.Now.Ticks.GetHashCode().的ToString( "×").ToUpper的()` (7认同)
  • “滴答”是可预测的,而不是线程安全的(因为可以从多个线程/进程中获得相同的“滴答”)。这使得它不适合临时文件名生成。生成 X..1..N 可能适用于面向用户的任务(即在资源管理器中复制),但对于服务器工作是可疑的。 (5认同)

KBB*_*ite 86

使用

Path.GetTempFileName()
Run Code Online (Sandbox Code Playgroud)

或使用新的GUID().

MSDN上的Path.GetTempFilename().

  • "GetTempFileName方法将引发[IOException](http://msdn.microsoft.com/en-us/library/system.io.ioexception.aspx),如果它用于创建超过65535个文件而不删除以前的临时文件".MSDN文章说. (19认同)
  • 但请注意,如果您创建了许多此类文件而不删除它们,那么`GetTempFileName()`可能会引发异常. (3认同)
  • 警告:`GetTempFileName` 将*创建*一个文件。这也意味着它*选择了临时路径位置*。另一方面,[`GetRandomFileName`](https://msdn.microsoft.com/en-us/library/system.io.path.getrandomfilename(v=vs.110).aspx) 适合生成 8.3 *文件名* 可以用于不同的路径。(我见过一些使用 GetTempFileName 和 File.Delete 只是为了在别处使用文件名的可怕代码。) (2认同)
  • 这是怎么得到投票的?我的意思是,你知道这个答案有多么误导吗?对于任何不知道 Path.GetTempFileName() 实际用途的人来说,这将是一场灾难。 (2认同)

Ram*_*eef 73

System.IO.Path.GetRandomFileName()
Run Code Online (Sandbox Code Playgroud)

MSDN上的Path.GetRandomFileName().

  • @RyBolt:既然你不需要自己种子,那么使用这种方法几乎没有什么可以记住的.我希望绝大多数开发人员不知道如何构建安全的加密系统. (13认同)

Mas*_*Mas 53

如果文件名的可读性不重要,那么GUID就像许多人建议的那样.但是,我发现查看具有1000个GUID文件名的目录是非常艰巨的排序.所以我通常使用一个静态字符串的组合,它给文件名一些上下文信息,一个时间戳和GUID.

例如:

public string GenerateFileName(string context)
{
    return context + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_" + Guid.NewGuid().ToString("N");
}

filename1 = GenerateFileName("MeasurementData");
filename2 = GenerateFileName("Image");
Run Code Online (Sandbox Code Playgroud)

这样,当我按文件名排序时,它将按上下文字符串自动对文件进行分组,并按时间戳排序.

请注意,Windows中的文件名限制为255个字符.

  • +1 建议包含*结合* GUID 的有用信息。- 顺便提一句:当您只需“右键单击 > 排序依据 > 日期”时,在文件名中包含日期和时间就有点多余了。 (2认同)

Mik*_*ain 20

这是一个算法,它根据提供的原始文件返回一个唯一可读的文件名.如果原始文件存在,则会逐渐尝试将索引附加到文件名,直到找到不存在的文件名.它将现有的文件名读入HashSet以检查冲突,因此它非常快(我的机器上每秒几百个文件名),它也是线程安全的,并且不会受到竞争条件的影响.

例如,如果您传递它test.txt,它将尝试按以下顺序创建文件:

test.txt
test (2).txt
test (3).txt
Run Code Online (Sandbox Code Playgroud)

您可以指定最大尝试次数,也可以将其保留为默认值.

这是一个完整的例子:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Kor*_*ray 7

我使用GetRandomFileName:

GetRandomFileName方法返回加密强大的随机字符串,可用作文件夹名称或文件名.与GetTempFileName不同,GetRandomFileName不会创建文件.当文件系统的安全性至关重要时,应该使用此方法而不是GetTempFileName.

例:

public static string GenerateFileName(string extension="")
{
    return string.Concat(Path.GetRandomFileName().Replace(".", ""),
        (!string.IsNullOrEmpty(extension)) ? (extension.StartsWith(".") ? extension : string.Concat(".", extension)) : "");
}
Run Code Online (Sandbox Code Playgroud)