Windowsで一時ディレクトリ名を取得する最良の方法は何ですか? GetTempPath
とGetTempFileName
を使用して一時ファイルを作成できることがわかりますが、Linux/BSDに相当するものはありますか mkdtemp
関数一時ディレクトリを作成しますか?
いいえ、mkdtempに相当するものはありません。最適なオプションは、 GetTempPath と GetRandomFileName の組み合わせを使用することです。
次のようなコードが必要になります。
public string GetTemporaryDirectory()
{
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
return tempDirectory;
}
Path.GetTempFileName()
をハッキングして、ディスク上の有効な擬似ランダムファイルパスを取得し、ファイルを削除して、同じファイルパスでディレクトリを作成します。
これにより、スコットドーマンの答えに対するクリスのコメントに従って、ファイルパスがしばらくまたはループで利用可能かどうかをチェックする必要がなくなります。
public string GetTemporaryDirectory()
{
string tempFolder = Path.GetTempFileName();
File.Delete(tempFolder);
Directory.CreateDirectory(tempFolder);
return tempFolder;
}
暗号的に安全なランダムな名前が本当に必要な場合は、スコットの答えをしばらく使用するか、ループを実行してディスク上にパスを作成しようとすることをお勧めします。
GetTempPath()、CoCreateGuid()、CreateDirectory()などのGUID作成関数を使用するのが好きです。
GUIDは一意性の可能性が高くなるように設計されており、誰かがGUID=そして、それらが存在する場合、CreateDirectory()はその存在を示すことに失敗します。)
@クリス。私も、一時ディレクトリがすでに存在する可能性があるというリモートのリスクに取りつかれていました。ランダムで暗号的に強力な議論についても、私を完全に満足させることはできません。
私のアプローチは、O/Sが2つの呼び出しがファイルを作成して両方とも成功しないようにする必要があるという基本的な事実に基づいています。 .NETデザイナーがディレクトリのWin32 API機能を非表示にすることを選択したことは少し驚くべきことです。私が使用するものは次のとおりです。
[DllImport(@"kernel32.dll", EntryPoint = "CreateDirectory", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreateDirectoryApi
([MarshalAs(UnmanagedType.LPTStr)] string lpPathName, IntPtr lpSecurityAttributes);
/// <summary>
/// Creates the directory if it does not exist.
/// </summary>
/// <param name="directoryPath">The directory path.</param>
/// <returns>Returns false if directory already exists. Exceptions for any other errors</returns>
/// <exception cref="System.ComponentModel.Win32Exception"></exception>
internal static bool CreateDirectoryIfItDoesNotExist([NotNull] string directoryPath)
{
if (directoryPath == null) throw new ArgumentNullException("directoryPath");
// First ensure parent exists, since the WIN Api does not
CreateParentFolder(directoryPath);
if (!CreateDirectoryApi(directoryPath, lpSecurityAttributes: IntPtr.Zero))
{
Win32Exception lastException = new Win32Exception();
const int ERROR_ALREADY_EXISTS = 183;
if (lastException.NativeErrorCode == ERROR_ALREADY_EXISTS) return false;
throw new System.IO.IOException(
"An exception occurred while creating directory'" + directoryPath + "'".NewLine() + lastException);
}
return true;
}
管理されていないp/invokeコードの「コスト/リスク」に見合う価値があるかどうかを判断できます。ほとんどの人はそうではありませんが、少なくともあなたには選択肢があります。
CreateParentFolder()は、学生に課題として残されています。 Directory.CreateDirectory()を使用します。ルートの場合はnullであるため、ディレクトリの親の取得に注意してください。
私は通常これを使用します:
/// <summary>
/// Creates the unique temporary directory.
/// </summary>
/// <returns>
/// Directory path.
/// </returns>
public string CreateUniqueTempDirectory()
{
var uniqueTempDir = Path.GetFullPath(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
Directory.CreateDirectory(uniqueTempDir);
return uniqueTempDir;
}
このディレクトリ名が一時パスに存在しないことを絶対に確認したい場合は、この一意のディレクトリ名が存在するかどうかを確認し、実際に存在する場合は別のディレクトリ名を作成する必要があります。
ただし、このGUIDベースの実装で十分です。この場合、私は問題の経験はありません。一部のMSアプリケーションは、GUIDベースの一時ディレクトリも使用します。
GetTempPath が正しい方法です。この方法についてのあなたの懸念は何なのか分かりません。その後、 CreateDirectory を使用して作成できます。
以下は、一時ディレクトリ名の衝突の問題を解決するためのやや強引なアプローチです。これは絶対的なアプローチではありませんが、フォルダーパスの衝突の可能性を大幅に減らします。
他のプロセスまたはアセンブリ関連の情報をディレクトリ名に追加して、衝突をさらに少なくする可能性がありますが、一時ディレクトリ名でそのような情報を表示することは望ましくない場合があります。フォルダー名をよりランダムに見せるために、時間関連のフィールドを組み合わせる順序を混ぜることもできます。私は個人的には、デバッグ中にそれらをすべて見つけやすいので、そのままにしておくことを好みます。
string randomlyGeneratedFolderNamePart = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
string timeRelatedFolderNamePart = DateTime.Now.Year.ToString()
+ DateTime.Now.Month.ToString()
+ DateTime.Now.Day.ToString()
+ DateTime.Now.Hour.ToString()
+ DateTime.Now.Minute.ToString()
+ DateTime.Now.Second.ToString()
+ DateTime.Now.Millisecond.ToString();
string processRelatedFolderNamePart = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
string temporaryDirectoryName = Path.Combine( Path.GetTempPath()
, timeRelatedFolderNamePart
+ processRelatedFolderNamePart
+ randomlyGeneratedFolderNamePart);
上記のように、Path.GetTempPath()はそれを行う1つの方法です。ユーザーがTEMP環境変数を設定している場合は、 Environment.GetEnvironmentVariable( "TEMP") を呼び出すこともできます。
アプリケーションでデータを永続化する手段として一時ディレクトリを使用することを計画している場合は、おそらく IsolatedStorage を構成/状態/などのリポジトリとして使用することを検討する必要があります...