Windowsで一時ディレクトリ名を取得する最良の方法は何ですか?を使用GetTempPath
しGetTempFileName
て一時ファイルを作成できることがわかりmkdtemp
ましたが、一時ディレクトリを作成するためのLinux / BSD 機能に相当するものはありますか?
Windowsで一時ディレクトリ名を取得する最良の方法は何ですか?を使用GetTempPath
しGetTempFileName
て一時ファイルを作成できることがわかりmkdtemp
ましたが、一時ディレクトリを作成するためのLinux / BSD 機能に相当するものはありますか?
回答:
いいえ、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;
}
暗号で保護されたランダムな名前が本当に必要な場合は、スコットの回答を調整して、whileまたはdoループを使用して、ディスク上にパスを作成し続けることができます。
@クリス。私も一時的なディレクトリがすでに存在する可能性があるというリモートのリスクに取りつかれていました。ランダムで暗号的に強力なものについての議論は、私を完全に満足させるものでもありません。
私のアプローチは、O / Sがファイルを作成するための2つの呼び出しを両方とも成功させてはならないという基本的な事実に基づいています。.NET設計者がディレクトリのWin32 API機能を非表示にすることを選択したのは少し意外です。これは、2回目のディレクトリの作成を試みたときにエラーを返すため、これをはるかに簡単にします。これが私が使うものです:
[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つの方法です。また、Environment.GetEnvironmentVariable( "TEMP")を呼び出すこともできます。ユーザーがTEMP環境変数を設定している場合は、ます。
アプリケーションでデータを永続化する手段として一時ディレクトリを使用することを計画している場合は、IsolatedStorageを構成/状態/その他のリポジトリとして使用することを検討する必要があります...