Création de dossiers temporaires
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 le nom de dossier incrémental ou les noms de dossier numérotés au hasard, mais je me demandais, comment d'autres personnes résolvent ce problème?
13 réponses
mise à Jour: Ajout De Fichier.Il existe de vérifier par commentaire (2012-Jun-19)
voici ce que j'ai utilisé dans VB.NET. Essentiellement le même que présenté, sauf que je ne voulais pas créer le dossier immédiatement.
L'avantage d'utiliser GetRandomFilename est qu'il ne crée pas de fichier, donc vous n'avez pas à nettoyer si vous utilisez le nom pour autre chose qu'un fichier. Comme l'utiliser pour le dossier nom.
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 Nom De Fichier Exemple:
voici une variation en utilisant un Guid pour obtenir le nom du dossier 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 Exemple:
Vous devez utiliser System.IO.Path.GetTempFileName()
crée un fichier temporaire à zéro octet nommé de façon unique sur le disque et retourne le chemin complet de ce fichier.
Vous pouvez utiliser System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName())
pour obtenir uniquement le dossier temp de l'information et de créer vos dossiers dedans
ils sont créés dans le dossier windows temp et c'est considéré comme une meilleure pratique
Juste pour préciser:
System.IO.Path.GetTempPath()
renvoie juste le chemin du dossier dans le dossier temporaire.
System.IO.Path.GetTempFileName()
renvoie le nom complet du fichier (y compris le chemin) ainsi:
System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName())
est redondante.
il y a une condition de course possible quand:
- création d'un fichier temporaire avec
GetTempFileName()
, de l'effacer, et de faire un dossier avec le même nom, ou - en utilisant
GetRandomFileName()
ouGuid.NewGuid.ToString
le nom d'un dossier et de créer le dossier plus tard
GetTempFileName()
après la suppression se produit, une autre application pourrait créer avec succès un fichier temp avec le même nom. CreateDirectory()
serait alors un échec.
de Même, entre l'appel de GetRandomFileName()
et la création de le répertoire un autre processus pourrait créer un fichier ou un répertoire avec le même nom, résultant à nouveau en CreateDirectory()
échec.
pour la plupart des applications, il est possible qu'un répertoire temporaire échoue en raison d'une condition de course. Il est extrêmement rare, après tout. Pour eux, ces courses peuvent souvent être ignoré.
dans le monde des scripts Unix shell, la création de fichiers et de répertoires temporaires d'une manière sûre et sans course est importante. Beaucoup de machines ont de multiples utilisateurs (hostiles) -- pensez hôte Web partagé -- et de nombreux scripts et applications ont besoin de créer en toute sécurité des fichiers et répertoires temp dans le répertoire shared /tmp. Voir créer en toute sécurité des fichiers temporaires dans des Scripts Shell pour une discussion sur la façon de créer des répertoires temp en toute sécurité à partir de scripts shell.
As @JonathanWright souligné, les conditions de concurrence qui existent pour les solutions:
- Créer un fichier temporaire avec
GetTempFileName()
, le supprimer, et de créer un dossier avec le même nom - Utiliser
GetRandomFileName()
ouGuid.NewGuid.ToString
pour créer un nom de Dossier aléatoire, Vérifiez s'il existe et créez-le si ce n'est pas le cas.
il est possible, cependant, de créer un répertoire temporaire unique atomiquement en utilisant le NTFS Transactionnels (TxF) API.
TxF a un CreateDirectoryTransacted()
fonction qui peut être invoquée via la plate-forme Invoke. Pour ce faire, je me suis 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.
Vous pouvez utiliser GetTempFileName pour créer un temporaire le fichier, puis supprimer et recréer ce fichier en tant que répertoire à la place.
Note: le lien ne fonctionne pas, copier/coller: http://msdn.microsoft.com/en-us/library/aa364991(SV.85).aspx
aussi longtemps que le nom du dossier n'a pas besoin d'être significatif, pourquoi ne pas utiliser un GUID pour eux?
réponses Combinées de @adam-wright et pix0r travail sera le meilleur à 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 le système.IO.Chemin.GetTempFileName indique que ce sera un fichier dans le chemin local de l'utilisateur (c.-à-d. non-roaming). C'est exactement là que vous le voulez pour des raisons de permissions et de sécurité.
Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))
@JonathanWright suggère que CreateDirectory va échouer quand il y a déjà un dossier. Si j'ai lu l'Annuaire.CreateDirectory dit 'Cet objet est retourné, qu'un répertoire existe ou non sur le chemin spécifié.'Ce qui signifie que vous ne détectez pas un dossier créé entre check exists et creating.
j'aime le CreateDirectoryTransacted () suggéré par @DanielTrebbien mais cette fonction est dépréciée.
La seule solution que je vois qui reste est de utilisez l'api c et appelez le' CreateDirectory ' là comme il fait erreur si le dossier existe si vous avez vraiment besoin d'être sûr de couvrir toute la condition de la course. Il en résulterait 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