Domanda

Sto lavorando a un programma che deve creare più cartelle temporanee per l'applicazione.Questi non saranno visti dall'utente.L'app è scritta in VB.net.Mi vengono in mente alcuni modi per farlo, come il nome della cartella incrementale o i nomi delle cartelle numerate casualmente, ma mi chiedevo, come gli altri risolvono questo problema?

È stato utile?

Soluzione

Aggiornamento: Aggiunto controllo File.Exists per commento (2012-Jun-19)

Ecco cosa ho usato in VB.NET.Essenzialmente lo stesso presentato, tranne che di solito non volevo creare immediatamente la cartella.

Il vantaggio di utilizzare Ottieni nome file casuale è che non crea un file, quindi non devi ripulire se usi il nome per qualcosa di diverso da un file.Come usarlo per il nome della cartella.

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

Casuale Esempio di nome file:

C:\Documents and Settings ome utente\Impostazioni locali emp\u3z5e0co.tvq


Ecco una variante che utilizza un Guid per ottenere il nome della cartella temporanea.

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

guida Esempio:

C:\Documents and Settings ome utente\Impostazioni locali emp\2dbc6db7-2d45-4b75-b27f-0bd492c60496

Altri suggerimenti

Devi usare System.IO.Path.GetTempFileName()

Crea un file temporaneo a zero byte con nome univoco sul disco e restituisce il percorso completo di quel file.

Puoi usare System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName()) per ottenere solo le informazioni sulla cartella temporanea e creare le tue cartelle lì

Vengono creati nella cartella temporanea di Windows e questa è considerata una procedura consigliata

Giusto per chiarire:

System.IO.Path.GetTempPath()

restituisce solo il percorso della cartella temporanea.

System.IO.Path.GetTempFileName()

restituisce il nome file completo (incluso il percorso), quindi questo:

System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName())

è ridondante.

Esiste una possibile condizione di competizione quando:

  • creando un file temporaneo con GetTempFileName(), eliminandolo e creando una cartella con lo stesso nome, oppure
  • utilizzando GetRandomFileName() O Guid.NewGuid.ToString per assegnare un nome a una cartella e creare la cartella in un secondo momento

Con GetTempFileName() dopo l'eliminazione, un'altra applicazione potrebbe creare correttamente un file temporaneo con lo stesso nome.IL CreateDirectory() allora fallirebbe.

Allo stesso modo, tra una chiamata e l'altra GetRandomFileName() e creando la directory un altro processo potrebbe creare un file o una directory con lo stesso nome, ottenendo nuovamente CreateDirectory() fallendo.

Per la maggior parte delle applicazioni è normale che una directory temporanea fallisca a causa di una condizione di competizione.Dopotutto è estremamente raro.Per loro, queste gare possono spesso essere ignorate.

Nel mondo dello scripting della shell Unix, creare file temporanei e directory in modo sicuro e senza gare è un grosso problema.Molte macchine hanno più utenti (ostili) - si pensi all'host web condiviso - e molti script e applicazioni devono creare in modo sicuro file e directory temporanei nella directory condivisa /tmp.Vedere Creazione sicura di file temporanei negli script di shell per una discussione su come creare in modo sicuro directory temporanee da script di shell.

Come @JonathanWright ha sottolineato, esistono condizioni di competizione per le soluzioni:

  • Crea un file temporaneo con GetTempFileName(), eliminalo e crea una cartella con lo stesso nome
  • Utilizzo GetRandomFileName() O Guid.NewGuid.ToString per creare un nome di cartella casuale, controlla se esiste e crealo in caso contrario.

È possibile, tuttavia, creare atomicamente una directory temporanea univoca utilizzando il file NTFS transazionale (TxF)API.

TxF ha un file CreateDirectoryTransacted() funzione che può essere richiamata tramite Platform Invoke.Per fare questo, mi sono adattato Il codice di Mohammad Elsheimy per aver chiamato 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());
}

Qualcosa di simile a...

using System.IO;

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

Directory.CreateDirectory(path);

Potresti generare un GUID per i nomi delle cartelle temporanee.

Finché non è necessario che il nome della cartella sia significativo, che ne dici di utilizzare un GUID per loro?

Puoi usare OttieniNomeFileTemp per creare un temporaneo file, quindi elimina e ricrea questo file come directory.

Nota:il link non ha funzionato, copia/incolla da: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

Le risposte combinate di @adam-wright e pix0r funzioneranno al meglio IMHO:


using System.IO;

string path = Path.GetTempPath() + Path.GetRandomFileName();

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

File.Delete(path);
Directory.CreateDirectory(path);

Il vantaggio di usare System.IO.Path.GetTempFileName è che sarà un file nel percorso locale (ovvero, non roaming) dell'utente.Questo è esattamente dove lo vorresti per autorizzazioni e motivi di sicurezza.

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

@JonathanWright suggerisce che CreateDirectory fallirà quando è già presente una cartella.Se leggo Directory.CreateDirectory dice "Questo oggetto viene restituito indipendentemente dal fatto che esista già una directory sul percorso specificato." Significa che non rilevi una cartella creata tra il controllo esiste e effettivamente la creazione.

Mi piace CreateDirectoryTransacted() suggerito da @DanielTrebbien ma questa funzione è deprecata.

L'unica soluzione che vedo rimasta è usare c api e chiamare il 'CreaDirectory' lì perché si verifica un errore se la cartella esiste se hai davvero bisogno di essere sicuro di coprire l'intera condizione di gara.Il risultato sarebbe qualcosa del genere:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top