Question

Je travaille sur un programme qui doit créer plusieurs dossiers temporaires pour l'application.Ceux-ci ne seront pas vus par l’utilisateur.L'application est écrite en VB.net.Je peux penser à quelques façons de le faire, comme un nom de dossier incrémentiel ou des noms de dossiers numérotés aléatoirement, mais je me demandais comment d'autres personnes résolvaient ce problème ?

Était-ce utile?

La solution

Mise à jour: Ajout de la vérification File.Exists par commentaire (2012-Jun-19)

Voici ce que j'ai utilisé dans VB.NET.Essentiellement identique à celui présenté, sauf que je ne voulais généralement pas créer le dossier immédiatement.

L'avantage d'utiliser GetRandomFilename est qu'il ne crée pas de fichier, vous n'avez donc pas besoin de nettoyer si vous utilisez le nom pour autre chose qu'un fichier.Comme l'utiliser pour le nom du dossier.

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éatoire Exemple de nom de fichier :

C:\Documents and Settings\username\Local Settings emp\u3z5e0co.tvq


Voici une variante utilisant un Guid pour obtenir le nom du dossier temporaire.

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

guide Exemple:

C:\Documents and Settings om d'utilisateur\Paramètres locaux emp\2dbc6db7-2d45-4b75-b27f-0bd492c60496

Autres conseils

Vous devez utiliser System.IO.Path.GetTempFileName()

Crée un fichier temporaire de zéro octet au nom unique sur le disque et renvoie le chemin complet de ce fichier.

Vous pouvez utiliser System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName()) pour obtenir uniquement les informations du dossier temporaire et y créer vos dossiers

Ils sont créés dans le dossier temporaire de Windows et cela est considéré comme une bonne pratique

Juste pour clarifier:

System.IO.Path.GetTempPath()

renvoie uniquement le chemin du dossier vers le dossier temporaire.

System.IO.Path.GetTempFileName()

renvoie le nom complet du fichier (y compris le chemin), donc ceci :

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

est redondant.

Il existe une condition de concurrence possible lorsque :

  • créer un fichier temporaire avec GetTempFileName(), en le supprimant et en créant un dossier du même nom, ou
  • en utilisant GetRandomFileName() ou Guid.NewGuid.ToString pour nommer un dossier et créer le dossier plus tard

Avec GetTempFileName() une fois la suppression effectuée, une autre application pourrait créer avec succès un fichier temporaire portant le même nom.Le CreateDirectory() échouerait alors.

De même, entre appeler GetRandomFileName() et en créant le répertoire, un autre processus pourrait créer un fichier ou un répertoire avec le même nom, ce qui entraînerait à nouveau CreateDirectory() échouer.

Pour la plupart des applications, il est normal qu'un répertoire temporaire échoue en raison d'une situation de concurrence critique.C'est extrêmement rare après tout.Pour eux, ces courses peuvent souvent être ignorées.

Dans le monde des scripts shell Unix, créer des fichiers et des répertoires temporaires en toute sécurité et sans race est une grosse affaire.De nombreuses machines ont plusieurs utilisateurs (hostiles) - pensez à un hébergeur partagé - et de nombreux scripts et applications doivent créer en toute sécurité des fichiers et des répertoires temporaires dans le répertoire partagé /tmp.Voir Création en toute sécurité de fichiers temporaires dans des scripts Shell pour une discussion sur la façon de créer en toute sécurité des répertoires temporaires à partir de scripts shell.

Comme @JonathanWright souligné, des conditions de course existent pour les solutions :

  • Créez un fichier temporaire avec GetTempFileName(), supprimez-le et créez un dossier du même nom
  • Utiliser GetRandomFileName() ou Guid.NewGuid.ToString pour créer un nom de dossier aléatoire, vérifiez s'il existe et créez-le sinon.

Il est cependant possible de créer atomiquement un répertoire temporaire unique en utilisant le NTFS transactionnel (TxF)API.

TxF a un CreateDirectoryTransacted() fonction qui peut être invoquée via Platform Invoke.Pour ce faire, j'ai adapté Le code de Mohammad Elsheimy Pour appeler 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());
}

Quelque chose comme...

using System.IO;

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

Directory.CreateDirectory(path);

Vous pouvez générer un GUID pour vos noms de dossiers temporaires.

Tant que le nom du dossier n'a pas besoin d'être significatif, que diriez-vous d'utiliser un GUID pour lui ?

Vous pouvez utiliser GetTempFileName pour créer un temporaire déposer, puis supprimez et recréez ce fichier en tant que répertoire.

Note:le lien ne fonctionne pas, copier/coller depuis : http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

Les réponses combinées de @adam-wright et pix0r fonctionneront le mieux à mon humble avis :


using System.IO;

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

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

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

L'avantage d'utiliser System.IO.Path.GetTempFileName est qu'il s'agira d'un fichier dans le chemin local (c'est-à-dire non itinérant) de l'utilisateur.C'est exactement là que vous le souhaiteriez pour des raisons d'autorisations et de sécurité.

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

@JonathanWright suggère que CreateDirectory échouera lorsqu'il existe déjà un dossier.Si je lis le répertoire.CreateDirectory, il dit: «Cet objet est renvoyé, si un répertoire sur le chemin spécifié existe déjà. Ce qui signifie que vous ne détectez pas un dossier créé entre le contrôle existe et la création.

J'aime le CreateDirectoryTransacted() suggéré par @DanielTrebbien mais cette fonction est obsolète.

La seule solution que je vois est d'utiliser l'API c et d'appeler le 'Créer le répertoire' Il y a une erreur si le dossier existe si vous devez vraiment être sûr de couvrir toute la condition de concurrence.Cela donnerait quelque chose comme ceci :

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top