web-dev-qa-db-ja.com

.NETで特定の拡張子を持つ一時ファイルを作成するにはどうすればよいですか?

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

私が今していることは

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

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

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

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

252
Brann

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

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

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

... annual石に衝突する年間リスクは170億回に1回と推定されています[19]。つまり、確率は約0.00000000006(6×10-11)であり、数十個の確率で1年で何兆ものUUIDがあり、1つ重複しています。つまり、次の100年間にわたって毎秒10億UUIDを生成した後にのみ、1つの複製が作成される可能性は約50%になります。地球上のすべての人が6億UUIDを所有している場合、1回の重複の可能性は約50%です。

編集:JaredParのコメントもご覧ください。

324
Mitch Wheat

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

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

選択した拡張子を含む完全なパスが返されます。

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

51
JaredPar
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回試行されます。

41
Maxence

代わりに 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拡張子を使用しましたが、好きなものを指定できます。また、使用後に一時ファイルが保持されるように、keepフラグをtrueに設定します。残念ながら、TempFileCollectionは拡張子ごとにランダムなファイルを1つ作成します。さらに多くの一時ファイルが必要な場合は、TempFileCollectionの複数のインスタンスを作成できます。

18
Mehmet Aras

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

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

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

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

8
Colonel Panic

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

string fileName;
do
{
    fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
} while (System.IO.File.Exists(fileName));
8
Matías

どうですか:

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

コンピュータが同じ瞬間に同じGUIDを生成することはほとんどありません。私がここで見る唯一の弱点は、DateTime.Now.Ticksが追加するパフォーマンスへの影響です。

6
I.R.Baboon

次のこともできます

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

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

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

C#の簡単な機能:

public static string GetTempFileName(string extension = "csv")
{
    return Path.ChangeExtension(Path.GetTempFileName(), extension);
}
3
RanchMobile

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

一時ファイル名は

  • ユニーク
  • 競合なし(まだ存在しない)
  • アトミック(同じ操作での名前とファイルの作成)
  • 推測しにくい

これらの要件があるため、このような獣を自分でプログラムするのはおかしい考えではありません。 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);
3

これは私にはうまくいくようです:ファイルの存在をチェックし、書き込み可能な場所であることを確認するためにファイルを作成します。正常に動作するはずです。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
2
Paolo Iommarini

これはあなたのために便利かもしれません...それは一時を作成することです。 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
2
Simon

これは、増分ファイル名を生成するためのシンプルだが効果的な方法です。現在のファイルを直接調べ(別の場所に簡単にポイントできます)、ベースのYourApplicationName * .txtでファイルを検索します(これも簡単に変更できます)。 0000から始まるため、最初のファイル名はYourApplicationName0000.txtになります。何らかの理由で、左と右の部分の間に(数字ではないことを意味する)ジャンクのあるファイル名がある場合、それらのファイルはtryparse呼び出しによって無視されます。

    public static string CreateNewOutPutFile()
    {
        const string RemoveLeft = "YourApplicationName";
        const string RemoveRight = ".txt";
        const string searchString = RemoveLeft + "*" + RemoveRight;
        const string numberSpecifier = "0000";

        int maxTempNdx = -1;

        string fileName;
        string [] Files = Directory.GetFiles(Directory.GetCurrentDirectory(), searchString);
        foreach( string file in Files)
        {
            fileName = Path.GetFileName(file);
            string stripped = fileName.Remove(fileName.Length - RemoveRight.Length, RemoveRight.Length).Remove(0, RemoveLeft.Length);
            if( int.TryParse(stripped,out int current) )
            {
                if (current > maxTempNdx)
                    maxTempNdx = current;
            }
        }
        maxTempNdx++;
        fileName = RemoveLeft + maxTempNdx.ToString(numberSpecifier) + RemoveRight;
        File.CreateText(fileName); // optional
        return fileName;
    }
0
Display name

インターネットで見つけた回答に基づいて、次のようにコードにアクセスします。

public static string GetTemporaryFileName()
{       
    string tempFilePath = Path.Combine(Path.GetTempPath(), "SnapshotTemp");
    Directory.Delete(tempFilePath, true);
    Directory.CreateDirectory(tempFilePath);
    return Path.Combine(tempFilePath, DateTime.Now.ToString("MMddHHmm") + "-" + Guid.NewGuid().ToString() + ".png");
}

そして、Jay HilyardによるC#クックブックとして、Stephen Teilhetは アプリケーションでの一時ファイルの使用 :を指摘しました。

  • 後で取得するために情報を一時的に保存する必要がある場合は、一時ファイルを使用する必要があります。

  • 覚えておく必要がある1つのことは、この一時ファイルを作成したアプリケーションが終了する前に、この一時ファイルを削除することです。

  • 削除されない場合、ユーザーが手動で削除するまで、ユーザーの一時ディレクトリに残ります。

0
Speedoops

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

 string tStamp = String.Format( "{0:yyyyMMdd.HHmmss}"、DateTime.Now); 
 string ProcID = Process.GetCurrentProcess()。Id.ToString(); 
 string tmpFolder = System.IO.Path.GetTempPath(); 
 string outFile = tmpFolder + ProcID + "_" + tStamp + ".txt"; 
0