.net - limpieza - eliminar archivos temporales windows 7
Creando carpetas temporales (13)
Algo como...
using System.IO;
string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
path = Path.GetTempPath() + Path.GetRandomFileName();
Directory.CreateDirectory(path);
Estoy trabajando en un programa que necesita crear varias carpetas temporales para la aplicación. Estos no serán vistos por el usuario. La aplicación está escrita en VB.net. Puedo pensar en algunas maneras de hacerlo, como el nombre de la carpeta incremental o los nombres de las carpetas con números al azar, pero me preguntaba cómo otras personas resuelven este problema.
La ventaja de utilizar System.IO.Path.GetTempFileName es que será un archivo en la ruta local del usuario (es decir, no itinerante). Aquí es exactamente donde lo desea para permisos y razones de seguridad.
Las respuestas combinadas de @ adam-wright y pix0r funcionarán mejor en mi humilde opinión:
using System.IO;
string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
path = Path.GetTempPath() + Path.GetRandomFileName();
File.Delete(path);
Directory.CreateDirectory(path);
Puede generar un GUID para sus nombres de carpetas temporales.
Puede usar GetTempFileName para crear un archivo temporal, luego eliminar y volver a crear este archivo como un directorio.
Nota: el enlace no funcionó, copiar / pegar desde: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx
Siempre que el nombre de la carpeta no tenga que ser significativo, ¿qué hay de usar un GUID para ellos?
Tienes que usar System.IO.Path.GetTempFileName()
Crea un archivo temporal de cero bytes con nombre exclusivo en el disco y devuelve la ruta completa de ese archivo.
Puede usar System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName())
para obtener solo la información de la carpeta temporal y crear sus carpetas allí
Se crean en la carpeta temp de Windows y eso se considera una buena práctica
Solo para aclarar:
System.IO.Path.GetTempPath()
devuelve solo la ruta de la carpeta a la carpeta temporal.
System.IO.Path.GetTempFileName()
devuelve el nombre completo del archivo (incluida la ruta) así que esto:
System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName())
es redundante
Hay una posible condición de carrera cuando:
- crear un archivo temporal con
GetTempFileName()
, eliminarlo y crear una carpeta con el mismo nombre, o - usando
GetRandomFileName()
oGuid.NewGuid.ToString
para nombrar una carpeta y crear la carpeta más tarde
Con GetTempFileName()
después de que se produce la eliminación, otra aplicación podría crear correctamente un archivo temporal con el mismo nombre. The CreateDirectory()
fallaría.
Del mismo modo, entre llamar a GetRandomFileName()
y crear el directorio, otro proceso podría crear un archivo o directorio con el mismo nombre, lo que también CreateDirectory()
resultado la CreateDirectory()
de CreateDirectory()
.
Para la mayoría de las aplicaciones, está bien que un directorio temporal falle debido a una condición de carrera. Es extremadamente raro después de todo. Para ellos, estas carreras a menudo pueden ser ignoradas.
En el mundo de scripts de shell de Unix, crear directorios y archivos temporales de una manera segura y sin carreras es un gran problema. Muchas máquinas tienen usuarios múltiples (hostiles), piense en un host web compartido, y muchos scripts y aplicaciones necesitan crear de forma segura archivos temporales y directorios en el directorio compartido / tmp. Consulte Creación segura de archivos temporales en scripts de shell para una discusión sobre cómo crear directorios temporales de forma segura desde scripts de shell.
Actualización: archivo agregado. Incluye verificación por comentario (2012-jun-19)
Esto es lo que he usado en VB.NET. Esencialmente el mismo que se presentó, excepto que generalmente no quería crear la carpeta de inmediato.
La ventaja de utilizar GetRandomFilename es que no crea un archivo, por lo que no tiene que limpiar si usa el nombre para algo que no sea un archivo. Me gusta usarlo para el nombre de la carpeta.
Private Function GetTempFolder() As String
Dim folder As String = Path.Combine(Path.GetTempPath, Path.GetRandomFileName)
Do While Directory.Exists(folder) or File.Exists(folder)
folder = Path.Combine(Path.GetTempPath, Path.GetRandomFileName)
Loop
Return folder
End Function
Ejemplo de nombre de archivo aleatorio :
C: / Documents and Settings / username / Configuración local / Temp / u3z5e0co.tvq
Aquí hay una variación usando un Guid para obtener el nombre de la carpeta temporal.
Private Function GetTempFolderGuid() As String
Dim folder As String = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString)
Do While Directory.Exists(folder) or File.Exists(folder)
folder = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString)
Loop
Return folder
End Function
Ejemplo de guid :
C: / Documents and Settings / username / Configuración local / Temp / 2dbc6db7-2d45-4b75-b27f-0bd492c60496
Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))
@JonathanWright sugiere que CreateDirectory fallará cuando ya haya una carpeta. Si leo Directory.CreateDirectory, dice ''Este objeto se devuelve independientemente de si ya existe un directorio en la ruta especificada''. Lo que significa que no se detecta una carpeta creada entre verificar y crear.
Me gusta el CreateDirectoryTransacted () sugerido por @DanielTrebbien pero esta función está en desuso.
La única solución que veo que queda es usar la c api y llamar a '' CreateDirectory '' allí como lo hace el error si la carpeta existe si realmente necesita asegurarse de cubrir toda la condición de carrera. Eso daría como resultado algo como esto:
Private Function GetTempFolder() As String
Dim folder As String
Dim succes as Boolean = false
Do While not succes
folder = Path.Combine(Path.GetTempPath, Path.GetRandomFileName)
success = c_api_create_directory(folder)
Loop
Return folder
End Function
Como @JonathanWright señaló , existen condiciones de carrera para las soluciones:
- Cree un archivo temporal con
GetTempFileName()
, elimínelo y cree una carpeta con el mismo nombre - Use
GetRandomFileName()
oGuid.NewGuid.ToString
para crear un nombre de carpeta aleatorio, compruebe si existe yGuid.NewGuid.ToString
si no.
Sin embargo, es posible crear un directorio temporal único atómicamente utilizando la API Transactional NTFS (TxF).
TxF tiene una función CreateDirectoryTransacted()
que se puede invocar a través de Invoke de plataforma. Para hacer esto, adapté el código de Mohammad Elsheimy para llamar a CreateFileTransacted()
:
// using System.ComponentModel;
// using System.Runtime.InteropServices;
// using System.Transactions;
[ComImport]
[Guid("79427a2b-f895-40e0-be79-b57dc82ed231")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IKernelTransaction
{
void GetHandle(out IntPtr pHandle);
}
// 2.2 Win32 Error Codes <http://msdn.microsoft.com/en-us/library/cc231199.aspx>
public const int ERROR_PATH_NOT_FOUND = 0x3;
public const int ERROR_ALREADY_EXISTS = 0xb7;
public const int ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION = 0x1aaf;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CreateDirectoryTransacted(string lpTemplateDirectory, string lpNewDirectory, IntPtr lpSecurityAttributes, IntPtr hTransaction);
/// <summary>
/// Creates a uniquely-named directory in the directory named by <paramref name="tempPath"/> and returns the path to it.
/// </summary>
/// <param name="tempPath">Path of a directory in which the temporary directory will be created.</param>
/// <returns>The path of the newly-created temporary directory within <paramref name="tempPath"/>.</returns>
public static string GetTempDirectoryName(string tempPath)
{
string retPath;
using (TransactionScope transactionScope = new TransactionScope())
{
IKernelTransaction kernelTransaction = (IKernelTransaction)TransactionInterop.GetDtcTransaction(Transaction.Current);
IntPtr hTransaction;
kernelTransaction.GetHandle(out hTransaction);
while (!CreateDirectoryTransacted(null, retPath = Path.Combine(tempPath, Path.GetRandomFileName()), IntPtr.Zero, hTransaction))
{
int lastWin32Error = Marshal.GetLastWin32Error();
switch (lastWin32Error)
{
case ERROR_ALREADY_EXISTS:
break;
default:
throw new Win32Exception(lastWin32Error);
}
}
transactionScope.Complete();
}
return retPath;
}
/// <summary>
/// Equivalent to <c>GetTempDirectoryName(Path.GetTempPath())</c>.
/// </summary>
/// <seealso cref="GetTempDirectoryName(string)"/>
public static string GetTempDirectoryName()
{
return GetTempDirectoryName(Path.GetTempPath());
}