c# - crear - ¿Creando un directorio temporal en Windows?
crear archivos temporales c# (8)
¿Cuál es la mejor manera de obtener un nombre de directorio temporal en Windows? Veo que puedo usar GetTempPath
y GetTempFileName
para crear un archivo temporal, pero ¿hay algún equivalente a la función mkdtemp
Linux / BSD para crear un directorio temporal?
@Chris. Yo también estaba obsesionado con el riesgo remoto de que ya existiera un directorio temporal. Las discusiones sobre el azar y la criptografía fuerte tampoco me satisfacen por completo.
Mi enfoque se basa en el hecho fundamental de que el O / S no debe permitir que 2 llamadas creen un archivo para que ambas tengan éxito. Es un poco sorprendente que los diseñadores de .NET elijan ocultar la funcionalidad de la API de Win32 para los directorios, lo que hace que esto sea mucho más fácil, porque devuelve un error cuando intenta crear un directorio por segunda vez. Esto es lo que uso:
[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;
}
Usted puede decidir si vale la pena el "costo / riesgo" del código p / invocación no administrado. La mayoría diría que no, pero al menos ahora tienes una opción.
CreateParentFolder () se deja como ejercicio para el alumno. Yo uso Directory.CreateDirectory (). Tenga cuidado al obtener el padre de un directorio, ya que es nulo cuando está en la raíz.
Aquí hay un enfoque algo más de fuerza bruta para resolver el problema de colisión para nombres de directorio temporales. No es un enfoque infalible, pero reduce significativamente las posibilidades de una colisión de ruta de carpeta.
Uno podría potencialmente agregar otra información relacionada con el proceso o el ensamblaje al nombre del directorio para hacer que la colisión sea aún menos probable, aunque hacer que tal información sea visible en el nombre del directorio temporal podría no ser deseable. También se podría mezclar el orden con el que los campos relacionados con el tiempo se combinan para hacer que los nombres de las carpetas parezcan más aleatorios. Personalmente prefiero dejarlo así simplemente porque es más fácil para mí encontrarlos durante la depuración.
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);
Como se mencionó anteriormente, Path.GetTempPath () es una forma de hacerlo. También puede llamar a Environment.GetEnvironmentVariable("TEMP") si el usuario tiene configurada una variable de entorno TEMP.
Si está planeando usar el directorio temporal como un medio de persistencia de datos en la aplicación, probablemente deba considerar el uso de IsolatedStorage como un repositorio para la configuración / estado / etc ...
Me gusta usar GetTempPath (), una función de creación de GUID como CoCreateGuid () y CreateDirectory ().
Un GUID está diseñado para tener una alta probabilidad de exclusividad, y también es altamente improbable que alguien cree manualmente un directorio con la misma forma que un GUID (y si lo hacen, entonces CreateDirectory () fallará indicando su existencia).
No, no hay equivalente a mkdtemp. La mejor opción es usar una combinación de GetTempPath y GetRandomFileName .
Necesitarías un código similar a esto:
public string GetTemporaryDirectory()
{
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
return tempDirectory;
}
Usualmente uso esto:
/// <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;
}
Si quiere estar absolutamente seguro de que este nombre de directorio no existirá en la ruta temporal, deberá verificar si este nombre de directorio exclusivo existe e intentar crear otro si realmente existe.
Pero esta implementación basada en GUID es suficiente. No tengo experiencia con ningún problema en este caso. Algunas aplicaciones de MS también usan directorios temporales basados en GUID.
GetTempPath es la forma correcta de hacerlo; No estoy seguro de cuál es su preocupación sobre este método. A continuación, puede usar CreateDirectory para hacerlo.
Path.GetTempFileName()
para darme una ruta de archivo pseudoaleatoria válida en el disco, luego elimino el archivo y creo un directorio con la misma ruta de archivo.
Esto evita la necesidad de verificar si el archivo está disponible en un momento o ciclo, según el comentario de Chris sobre la respuesta de Scott Dorman.
public string GetTemporaryDirectory()
{
string tempFolder = Path.GetTempFileName();
File.Delete(tempFolder);
Directory.CreateDirectory(tempFolder);
return tempFolder;
}
Si realmente necesita un nombre aleatorio criptográficamente seguro, puede adaptar la respuesta de Scott para usar un ciclo while o do para seguir intentando crear una ruta en el disco.