使用随机数使文件名唯一是安全的吗?

Safe to use random numbers to make filenames unique?

我正在编写一个主要处理数据并输出许多文件的程序。每次使用都不可能生成超过 10-20 个文件。我只是想知道使用这种方法生成唯一文件名是否是个好主意? rand 是否有可能选择 x,然后在 10 个实例中再次选择 x。使用 random(); 是个好主意吗?任何输入将不胜感激!

Random rand = new Random ();
int randNo = rand.Next(100000,999999)l

using (var write = new StreamWriter("C:\test" + randNo + ".txt") 
{
// Stuff
}

I just wanted to know if using this method to generate unique filenames is a good idea?

没有。唯一性不是 属性 的随机性。随机意味着结果值不以任何方式依赖于先前的状态。这意味着重复是可能的。您可以连续多次获得相同的数字(尽管不太可能)。

如果您想要唯一的值,请使用 GUID:

Guid.NewGuid();

正如下面的评论所指出的,这个解决方案并不完美。但我认为这足以解决手头的问题。这个想法是 Random 被设计成随机的,而 Guid 被设计成唯一的。在数学上,"random" 和 "unique" 是需要解决的重要问题。

这些实现都不是 100% 完美的。但关键是简单地使用两者中正确的一种来实现预期的功能。

或者,打个比方...如果你想把钉子锤进一块木头,是不是100%保证锤子能成功?不会。锤子在接触钉子时碎裂的可能性非零。但我仍然会伸手去拿锤子,而不是陪审团用螺丝刀来操纵东西。

有所谓的Birthday Paradox...如果你生成一些随机数(任何数字> 1),遇到"collision"的可能性增加...如果你生成sqrt (numberofpossiblevalues) 值,发生碰撞的可能性约为 50%...所以您有 799998 个可能的值...sqrt(799998) 为 894...它非常低...对您的程序进行 45-90 次调用你有 50% 的几率发生碰撞。

注意随机是随机的,如果你生成两个随机数,碰撞的可能性非零,如果你生成numberofpossiblevalues + 1个随机数,碰撞的可能性为1.

现在...有人会告诉您 Guid.NewGuid 将生成 始终唯一的 值。他们是非常好的蛇油的卖家。如 MSDN 中所写,在 Guid.NewGuid 页面中...

The chance that the value of the new Guid will be all zeros or equal to any other Guid is very low.

机会不是 0,它非常(非常非常我会补充)低!这里生日悖论激活......现在......Microsoft Guid 有 122 位的 "random" 部分和 6 位的 "fixed" 部分,50%的碰撞机会发生在 2.3x10^18 左右。这是一个很大的数字! 1%的碰撞几率是在3.27x10^17之后...还是很大的数字!

请注意,Microsoft 使用强大的随机数生成器生成这 122 位:https://msdn.microsoft.com/en-us/library/bb417a2c-7a58-404f-84dd-6b494ecf0d13#id9

Windows uses the cryptographic PRNG from the Cryptographic API (CAPI) and the Cryptographic API Next Generation (CNG) for generation of Version 4 GUIDs.

因此,虽然 Guid.NewGuid 生成的整个 Guid 不是完全随机的(因为 6 位是固定的),但它仍然是相当随机的。

如果您想要生成唯一值,可以使用专门用于生成唯一标识值的工具,即全局唯一标识符 (GUID)。

var guid = Guid.NewGuid();

将找出创造这种独特价值的最佳方式的问题留给其他人。

我认为在文件名中添加文件的创建日期和时间是个好主意,以确保文件不会重复。如果你想让它更独特(如果你的 10 个文件同时保存),你也可以添加随机数。

所以文件名可能是file06182015112300.txt(显示月、日、年、时、分和秒)

如果你想使用那种格式的文件,并且你知道你不会 运行 出未使用的数字,检查你生成的随机数是否尚未被使用会更安全,如下所示:

Random rand = new Random();
string filename = "";
do
{
    int randNo = rand.Next(100000, 999999);
    filename = "C:\test" + randNo + ".txt";
} while (File.Exists(filename));
using (var write = new StreamWriter(filename))
{
//Stuff
}

不,这不是在 .Net 中创建临时文件名的正确方法。

正确的方法是使用 Path.GetTempFileName (creates file immediatedly) or Path.GetRandomFileName(创建高质量的随机名称)。

请注意,RandomGuid.NewGuid()DateTime.Now 生成少量文件名并没有太大问题,如其他答案所述,但使用 预期 用于特定目的导致代码更容易 read/prove 正确性。