我需要用.csv扩展名生成一个唯一的临时文件。

我现在做的是

string filepath = System.IO.Path.GetTempFileName().Replace(".tmp", ".csv");

但是,这并不能保证.csv文件是唯一的。

我知道发生碰撞的可能性非常低(特别是如果您考虑到我没有删除.tmp文件的话),但是这段代码对我来说不太好。

当然,我可以手动生成随机文件名,直到我最终找到一个唯一的文件名(这应该不是问题),但我很想知道其他人是否已经找到了处理这个问题的好方法。


当前回答

我混合@Maxence和@Mitch小麦答案记住,我想要GetTempFileName方法的语义(文件名是创建的新文件的名称)添加扩展名首选。

string GetNewTempFile(string extension)
{
    if (!extension.StartWith(".")) extension="." + extension;
    string fileName;
    bool bCollisions = false;
    do {
        fileName = Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString() + extension);
        try
        {
            using (new FileStream(fileName, FileMode.CreateNew)) { }
            bCollisions = false;
        }
        catch (IOException)
        {
            bCollisions = true;
        }
    }
    while (bCollisions);
    return fileName;
}

其他回答

唯一的:保证(统计上)唯一的:

string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv"; 

(引用维基上关于碰撞概率的文章:

...one's annual risk of being hit by a meteorite is estimated to be one chance in 17 billion [19], that means the probability is about 0.00000000006 (6 × 10−11), equivalent to the odds of creating a few tens of trillions of UUIDs in a year and having one duplicate. In other words, only after generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%. The probability of one duplicate would be about 50% if every person on earth owns 600 million UUIDs

编辑:请参阅JaredPar的评论。

这对我来说似乎工作得很好:它检查文件是否存在,并创建文件以确保它是一个可写的位置。 应该可以正常工作,你可以将其更改为直接返回FileStream(这通常是临时文件所需要的):

private string GetTempFile(string fileExtension)
{
  string temp = System.IO.Path.GetTempPath();
  string res = string.Empty;
  while (true) {
    res = string.Format("{0}.{1}", Guid.NewGuid().ToString(), fileExtension);
    res = System.IO.Path.Combine(temp, res);
    if (!System.IO.File.Exists(res)) {
      try {
        System.IO.FileStream s = System.IO.File.Create(res);
        s.Close();
        break;
      }
      catch (Exception) {

      }
    }
  }
  return res;
} // GetTempFile

您还可以执行以下操作

string filepath = Path.ChangeExtension(Path.GetTempFileName(), ".csv");

这也符合预期

string filepath = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");

试试这个功能…

public static string GetTempFilePathWithExtension(string extension) {
  var path = Path.GetTempPath();
  var fileName = Path.ChangeExtension(Guid.NewGuid().ToString(), extension);
  return Path.Combine(path, fileName);
}

它将返回一个完整的路径和您选择的扩展名。

注意,它不能保证产生唯一的文件名,因为从技术上讲,其他人可能已经创建了该文件。然而,有人猜出你的应用产生的下一个guid并创建它的机会非常非常低。假设这是唯一的是很安全的。

c++的GetTempFileName的MSDN文档讨论了你的问题并回答了它:

GetTempFileName不能保证文件名是唯一的。 只使用uUnique参数的下16位。如果lpPathName和lpPrefixString参数保持不变,这将限制GetTempFileName最多为65,535个唯一的文件名。 由于用于生成文件名的算法,当使用相同的前缀创建大量文件时,GetTempFileName的性能可能很差。在这种情况下,建议您基于guid构造惟一的文件名。