Windowsで一時ディレクトリ名を取得するための最良の方法は何ですか?GetTempPath
とを使用して一時ファイルを作成できることはわかりましたが、一時ディレクトリを作成するためのLinux / BSD関数にGetTempFileName
相当するものはありますか?mkdtemp
9 に答える
いいえ、mkdtempに相当するものはありません。最良のオプションは、GetTempPathとGetRandomFileNameの組み合わせを使用することです。
次のようなコードが必要になります。
public string GetTemporaryDirectory()
{
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
return tempDirectory;
}
私は、GetTempPath()、CoCreateGuid() のような GUID 作成関数、および CreateDirectory() を使用するのが好きです。
GUID は高い確率で一意になるように設計されており、誰かが GUID と同じ形式のディレクトリを手動で作成する可能性はほとんどありません (作成した場合、CreateDirectory() はその存在を示すことに失敗します)。
@クリス。私も、一時ディレクトリがすでに存在している可能性があるというリモート リスクに取りつかれていました。ランダムで暗号学的に強いという議論も、私を完全に満足させるものではありません。
私のアプローチは、O/S がファイルを作成するための 2 つの呼び出しが両方とも成功することを許可してはならないという基本的な事実に基づいています。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 ベースの一時ディレクトリも使用します。
これは、一時ディレクトリ名の衝突の問題を解決するための、やや強引なアプローチです。これは間違いのないアプローチではありませんが、フォルダー パスの衝突の可能性を大幅に減らします。
他のプロセスまたはアセンブリ関連の情報をディレクトリ名に追加して、衝突の可能性をさらに低くすることもできますが、そのような情報を一時ディレクトリ名に表示することは望ましくない場合があります。フォルダ名がよりランダムに見えるように、時間関連のフィールドを組み合わせる順序を混合することもできます。個人的には、デバッグ中にそれらすべてを見つけやすいという理由だけで、そのままにしておくことを好みます。
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を構成/状態/その他のリポジトリとして使用することを検討する必要があります...
GetTempPathはそれを行う正しい方法です。この方法についてのあなたの懸念が何であるかはわかりません。その後、 CreateDirectoryを使用して作成できます。