303

拡張子が .csv の一意の一時ファイルを生成する必要があります。

私が今していることは、

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

ただし、これは私の .csv ファイルが一意であることを保証するものではありません。

衝突が発生する可能性は非常に低いことはわかっていますが (特に、.tmp ファイルを削除しないと考えている場合)、このコードは私には見栄えがよくありません。

もちろん、最終的に一意のファイル名が見つかるまで手動でランダムなファイル名を生成することもできますが (これは問題にならないはずです)、他の人がこの問題に対処する良い方法を見つけたかどうか知りたいです。

4

17 に答える 17

394

(統計的に) 一意であることが保証されています。

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

(衝突の確率に関するウィキの記事から引用するには:

...隕石に当たる年間リスクは 170 億分の 1 の確率であると推定されています [19]。これは、その確率が約 0.00000000006 (6 × 10−11) であることを意味します。 1 年間で数兆の UUID があり、1 つの重複があります。言い換えれば、次の 100 年間、毎秒 10 億の UUID を生成した後で初めて、複製が 1 つだけ作成される確率は約 50% になります。地球上のすべての人が 6 億の UUID を所有している場合、1 つの重複の確率は約 50% になります。

編集: JaredPar のコメントも参照してください。

于 2009-02-24T12:29:14.637 に答える
62

この機能を試してみてください...

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

選択した拡張子を含むフル パスが返されます。

他の誰かが技術的にそのファイルをすでに作成している可能性があるため、一意のファイル名を生成することは保証されていないことに注意してください。ただし、誰かがアプリによって生成される次の GUID を推測して作成する可能性は非常に低いです。これがユニークであると想定するのはかなり安全です。

于 2009-02-24T12:38:13.040 に答える
53
public static string GetTempFileName(string extension)
{
  int attempt = 0;
  while (true)
  {
    string fileName = Path.GetRandomFileName();
    fileName = Path.ChangeExtension(fileName, extension);
    fileName = Path.Combine(Path.GetTempPath(), fileName);

    try
    {
      using (new FileStream(fileName, FileMode.CreateNew)) { }
      return fileName;
    }
    catch (IOException ex)
    {
      if (++attempt == 10)
        throw new IOException("No unique temporary file name is available.", ex);
    }
  }
}

注: これは Path.GetTempFileName のように機能します。ファイル名を予約するために空のファイルが作成されます。Path.GetRandomFileName(); によって衝突が発生した場合は、10 回試行します。

于 2012-04-14T09:20:27.913 に答える
19

代わりにSystem.CodeDom.Compiler.TempFileCollectionを使用することもできます。

string tempDirectory = @"c:\\temp";
TempFileCollection coll = new TempFileCollection(tempDirectory, true);
string filename = coll.AddExtension("txt", true);
File.WriteAllText(Path.Combine(tempDirectory,filename),"Hello World");

ここでは txt 拡張子を使用しましたが、必要に応じて指定できます。また、キープ フラグを true に設定して、一時ファイルが使用後に保持されるようにします。残念ながら、TempFileCollection は拡張子ごとにランダムなファイルを 1 つ作成します。さらに一時ファイルが必要な場合は、TempFileCollection の複数のインスタンスを作成できます。

于 2009-07-14T02:03:10.703 に答える
11

ファイルが存在するかどうかを確認しないのはなぜですか?

string fileName;
do
{
    fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
} while (System.IO.File.Exists(fileName));
于 2009-02-24T13:25:06.157 に答える
10

C++ の GetTempFileNameに関する MSDN ドキュメントでは、懸念事項について説明し、回答しています。

GetTempFileName は、ファイル名が一意であることを保証できません

uUnique パラメータの下位 16 ビットのみが使用されます。これにより、lpPathName パラメーターと lpPrefixString パラメーターが同じままである場合、GetTempFileName は最大 65,535 個の一意のファイル名に制限されます。

ファイル名の生成に使用されるアルゴリズムが原因で、同じプレフィックスを持つ多数のファイルを作成すると、GetTempFileName のパフォーマンスが低下する可能性があります。このような場合は、GUID に基づいて一意のファイル名を作成することをお勧めします

于 2012-10-01T15:18:31.347 に答える
6

次のこともできます

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

これも期待どおりに機能します

string filepath = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");
于 2009-02-24T14:39:08.350 に答える
6

どうですか:

Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString() + "_" + Guid.NewGuid().ToString() + ".csv")

コンピューターが同じ Guid を同じ瞬間に生成する可能性は非常に低いです。ここで見られる唯一の弱点は、DateTime.Now.Ticks が追加するパフォーマンスへの影響です。

于 2010-07-27T08:12:39.917 に答える
3

私の意見では、ここで提案されたほとんどの回答は最適ではありません。最も近いものは、Brann によって最初に提案された元のものです。

一時ファイル名は

  • 個性的
  • コンフリクトフリー(まだ存在しない)
  • Atomic (同一操作で名前とファイルを作成)
  • 推測しにくい

これらの要件があるため、そのような野獣を自分でプログラムするのは良い考えではありません。IO ライブラリを書いている頭の良い人は、ロック (必要な場合) などについて心配しています。したがって、System.IO.Path.GetTempFileName() を書き換える必要はないと思います。

不器用に見えても、これは仕事をするはずです:

//Note that this already *creates* the file
string filename1 = System.IO.Path.GetTempFileName()
// Rename and move
filename = filename.Replace(".tmp", ".csv");
File.Move(filename1 , filename);
于 2015-01-06T08:19:43.793 に答える
2

これは私にとってはうまくいくようです。ファイルの存在をチェックし、書き込み可能な場所であることを確認するためにファイルを作成します。正常に動作する場合は、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
于 2011-07-25T12:52:43.627 に答える
2

これはあなたにとって便利かもしれません...それは一時を作成することです。フォルダを取得し、VB.NET で文字列として返します。

C# に簡単に変換可能:

Public Function GetTempDirectory() As String
    Dim mpath As String
    Do
        mpath = System.IO.Path.Combine(System.IO.Path.GetTempPath, System.IO.Path.GetRandomFileName)
    Loop While System.IO.Directory.Exists(mpath) Or System.IO.File.Exists(mpath)
    System.IO.Directory.CreateDirectory(mpath)
    Return mpath
End Function
于 2011-05-30T12:49:30.917 に答える
0

これは私がやっていることです:

string tStamp = String.Format("{0:yyyyMMdd.HHmmss}", DateTime.Now);
文字列 ProcID = Process.GetCurrentProcess().Id.ToString();
文字列 tmpFolder = System.IO.Path.GetTempPath();
文字列 outFile = tmpFolder + ProcID + "_" + tStamp + ".txt";
于 2011-04-15T20:13:27.357 に答える
-2

私はあなたがこれを試してみるべきだと思います:

string path = Path.GetRandomFileName();
path = Path.Combine(@"c:\temp", path);
path = Path.ChangeExtension(path, ".tmp");
File.Create(path);

一意のファイル名を生成し、指定された場所にそのファイル名でファイルを作成します。

于 2011-08-22T07:16:55.863 に答える