Pregunta

Estoy trabajando en un programa que necesita para crear múltiples carpetas temporales para la aplicación.No va a ser visto por el usuario.La aplicación está escrita en VB.net.Se me ocurren un par de formas de hacerlo como incremental nombre de la carpeta o al azar de la carpeta numerada de los nombres, pero me preguntaba, cómo otras personas a resolver este problema?

¿Fue útil?

Solución

Actualización: Archivo Agregado.Existe verificación por comentario (2012-Jun-19)

Esto es lo que yo he usado en VB.NET.Esencialmente el mismo que el presentado, excepto que normalmente no desea crear la carpeta de inmediato.

La ventaja de utilizar GetRandomFilename es que no crea un archivo, de modo que usted no tiene que limpiar si el usar el nombre para algo distinto a un archivo.Como el uso que del 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

Al azar Nombre Del Archivo Ejemplo:

C:\Documents and Settings ombre de usuario\Configuración Local emp\u3z5e0co.tvq


He aquí una variación utilizando un Guid para obtener el nombre de la carpeta temp.

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

guid Ejemplo:

C:\Documents and Settings ombre de usuario\Configuración Local emp\2dbc6db7-2d45-4b75-b27f-0bd492c60496

Otros consejos

Usted tiene que usar System.IO.Path.GetTempFileName()

Crea un nombre único, de cero bytes archivo temporal en el disco y devuelve la ruta completa del archivo.

Puede utilizar System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName()) para obtener sólo la carpeta temp de la información, y crear sus carpetas de allí

Se crean en la carpeta temp de windows y que se considere la posibilidad de una mejor práctica

Solo para aclarar:

System.IO.Path.GetTempPath()

retorna la ruta de la carpeta a la carpeta temp.

System.IO.Path.GetTempFileName()

devuelve el nombre completo del archivo (incluyendo la ruta de acceso), 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(), borrar la cuenta, y haciendo una carpeta con el mismo nombre, o
  • el uso de GetRandomFileName() o Guid.NewGuid.ToString el nombre de una carpeta y la creación de la carpeta posteriormente

Con GetTempFileName() después de la eliminación se produce, otra aplicación con éxito podría crear un archivo temporal con el mismo nombre.El CreateDirectory() sería entonces fallar.

Del mismo modo, entre llamar a GetRandomFileName() y la creación del directorio de otro proceso podría crear un archivo o directorio con el mismo nombre, lo que resulta en CreateDirectory() fallando.

Para la mayoría de las aplicaciones que está bien para un directorio temporal a fallar debido a una condición de carrera.Es extremadamente raro, después de todo.Para ellos, estas carreras, a menudo puede ser ignorado.

En el shell de Unix scripting mundo, la creación de temp archivos y directorios en una carrera segura-de manera libre es una gran oferta.Muchas máquinas tienen múltiples (hostil) a los usuarios -- creo alojamiento web compartido -- y muchos scripts y aplicaciones que necesitan para crear de manera segura temp archivos y directorios en el directorio /tmp.Ver Con seguridad la Creación de Archivos Temporales en los Scripts de Shell para una discusión sobre la forma más segura de crear directorios temporales de secuencias de comandos de shell.

Como @JonathanWright señaló, raza existen condiciones para las soluciones:

  • Crear un archivo temporal con GetTempFileName(), eliminar y crear una carpeta con el mismo nombre
  • Uso GetRandomFileName() o Guid.NewGuid.ToString para crear un azar el nombre de la carpeta, comprobar si ya existe, y cree que si no.

Es posible, sin embargo, para crear un único directorio temporal atómicamente mediante la utilización de la NTFS transaccional (TxF) de la API.

TxF tiene un CreateDirectoryTransacted() función que se puede invocar a través de la invocación de Plataforma.Para ello, me he adaptado Mohammad Elsheimy del código 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());
}

Algo así como...

using System.IO;

string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
 path = Path.GetTempPath() + Path.GetRandomFileName();

Directory.CreateDirectory(path);

Se podría generar un GUID para la carpeta temporal de los nombres.

Mientras el nombre de la carpeta no tienen que ser significativos, como sobre el uso de un GUID para ellos?

Puede utilizar GetTempFileName para crear un temporal archivo, a continuación, eliminar y volver a crear este archivo como un directorio en su lugar.

Nota:el enlace no funciona, copiar/pegar desde: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

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);

La ventaja de utilizar el Sistema.IO.Ruta de acceso.GetTempFileName es que será un archivo en el local del usuario (es decir, no móviles) ruta de acceso.Esto es exactamente donde usted lo desee para permisos y razones de seguridad.

Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))

@JonathanWright sugiere CreateDirectory se producirá cuando ya existe una carpeta.Si he leído Directorio.CreateDirectory dice " Este objeto es devuelto independientemente de si un directorio en la ruta de acceso especificada ya existe.' Lo que significa que no detectan una carpeta creada entre el cheque existe y en realidad la creación.

Me gusta la CreateDirectoryTransacted() sugerida por @DanielTrebbien pero esta función está obsoleta.

La única solución que veo que queda es usar la api de c y llamar a la 'CreateDirectory"no hay como error si existe la carpeta si usted realmente necesita para asegurarse de cubrir la totalidad de la condición de carrera.Que el resultado sería 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top