J'ai besoin de générer un fichier temporaire unique avec une extension .csv.
Ce que je fais maintenant c'est
string filename = System.IO.Path.GetTempFileName().Replace(".tmp", ".csv");
Toutefois, cela ne garantit pas que mon fichier .csv sera unique.
Je sais que les risques de collision sont très faibles (surtout si vous considérez que je ne supprime pas les fichiers .tmp), mais ce code ne me semble pas bon.
Bien sûr, je pouvais générer manuellement des noms de fichiers aléatoires jusqu'à ce que je trouve finalement un nom unique (ce qui ne devrait pas poser de problème), mais je suis curieux de savoir si d'autres personnes ont trouvé un moyen agréable de traiter ce problème.
Garanti d'être unique (statistiquement):
string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
(Pour citer l'article du wiki sur la probabilité d'une collision:
... le risque annuel d'être frappé par une météorite est estimé à une chance sur 17 milliards [19], ce qui signifie que la probabilité est d'environ 0,00000000006 (6 × 10−11), ce qui équivaut à la probabilité de créer quelques dizaines de des milliards d’UIDU en un an et en ayant un duplicata. En d’autres termes, ce n’est qu’après avoir généré 1 milliard d’UUID par seconde pour les 100 prochaines années que la probabilité de créer un seul duplicata serait d’environ 50%. La probabilité d'un duplicata serait d'environ 50% si chaque habitant de la planète possède 600 millions d'UUID
EDIT: S'il vous plaît voir également les commentaires de JaredPar.
Essayez cette fonction ...
public static string GetTempFilePathWithExtension(string extension) {
var path = Path.GetTempPath();
var fileName = Guid.NewGuid().ToString() + extension;
return Path.Combine(path, fileName);
}
Il retournera un chemin complet avec l'extension de votre choix.
Notez qu'il n'est pas garanti de produire un nom de fichier unique, car quelqu'un d'autre aurait déjà techniquement créé ce fichier. Cependant, les chances que quelqu'un devine le prochain guide généré par votre application et le crée soient très très faible. Il est assez prudent de supposer que cela sera unique.
public static string GetTempFileName(string extension)
{
int attempt = 0;
while (true)
{
string fileName = Path.GetRandomFileName();
fileName = Path.ChangeExtension(fileName, extension);
fileName = Path.Combine(Path.GetTempPath(), fileName);
try
{
using (new FileStream(fileName, FileMode.CreateNew)) { }
return fileName;
}
catch (IOException ex)
{
if (++attempt == 10)
throw new IOException("No unique temporary file name is available.", ex);
}
}
}
Remarque: cela fonctionne comme Path.GetTempFileName. Un fichier vide est créé pour réserver le nom du fichier. Il fait 10 tentatives, en cas de collisions générées par Path.GetRandomFileName ();
Vous pouvez également utiliser System.CodeDom.Compiler.TempFileCollection .
string tempDirectory = @"c:\\temp";
TempFileCollection coll = new TempFileCollection(tempDirectory, true);
string filename = coll.AddExtension("txt", true);
File.WriteAllText(Path.Combine(tempDirectory,filename),"Hello World");
Ici, j'ai utilisé une extension txt mais vous pouvez spécifier ce que vous voulez. J'ai également défini l'indicateur keep sur true pour que le fichier temporaire soit conservé après utilisation. Malheureusement, TempFileCollection crée un fichier aléatoire par extension. Si vous avez besoin de plus de fichiers temporaires, vous pouvez créer plusieurs instances de TempFileCollection.
Pourquoi ne pas vérifier si le fichier existe?
string fileName;
do
{
fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
} while (System.IO.File.Exists(fileName));
La documentation MSDN pour GetTempFileName de C++ décrit votre problème et y répond:
GetTempFileName n'est pas en mesure de garantir que le nom du fichier est unique .
Seuls les 16 bits inférieurs du paramètre uUnique sont utilisés. Cela limite GetTempFileName à un maximum de 65 535 noms de fichiers uniques si les paramètres lpPathName et lpPrefixString restent identiques.
En raison de l'algorithme utilisé pour générer les noms de fichiers, GetTempFileName peut être moins performant lors de la création d'un grand nombre de fichiers avec le même préfixe. Dans de tels cas, , il est recommandé de créer des noms de fichier uniques basés sur des GUID .
Que diriez-vous:
Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString() + "_" + Guid.NewGuid().ToString() + ".csv")
Il est hautement improbable que l'ordinateur génère le même Guid au même instant. La seule faiblesse que je vois ici est l’impact de la performance que DateTime.Now.Ticks ajoutera.
Vous pouvez également faire ce qui suit
string filename = Path.ChangeExtension(Path.GetTempFileName(), ".csv");
et cela fonctionne aussi comme prévu
string filename = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");
Fonction facile en C #:
public static string GetTempFileName(string extension = "csv")
{
return Path.ChangeExtension(Path.GetTempFileName(), extension);
}
À mon avis, la plupart des réponses proposées ici sont sous-optimales. Celui qui se rapproche le plus est celui proposé initialement par Brann.
Un nom de fichier temporaire doit être
En raison de ces exigences, ce n’est pas une bonne idée de programmer vous-même une telle bête. Smart People en train d'écrire IO Les bibliothèques s'inquiètent de choses comme le verrouillage (si nécessaire), etc. Par conséquent, je ne vois pas la nécessité de réécrire System.IO.Path.GetTempFileName ().
Ceci, même s'il a l'air maladroit, devrait faire l'affaire:
//Note that this already *creates* the file
string filename1 = System.IO.Path.GetTempFileName()
// Rename and move
filename = filename.Replace(".tmp", ".csv");
File.Move(filename1 , filename);
Cela semble fonctionner correctement pour moi: il vérifie l'existence du fichier et le crée pour s'assurer qu'il s'agit d'un emplacement inscriptible. Si cela fonctionne correctement, vous pouvez le changer pour renvoyer directement FileStream (qui est normalement ce dont vous avez besoin pour un fichier temporaire):
private string GetTempFile(string fileExtension)
{
string temp = System.IO.Path.GetTempPath();
string res = string.Empty;
while (true) {
res = string.Format("{0}.{1}", Guid.NewGuid().ToString(), fileExtension);
res = System.IO.Path.Combine(temp, res);
if (!System.IO.File.Exists(res)) {
try {
System.IO.FileStream s = System.IO.File.Create(res);
s.Close();
break;
}
catch (Exception) {
}
}
}
return res;
} // GetTempFile
Cela pourrait être pratique pour vous ... C'est pour créer un temp. dossier et le renvoyer sous forme de chaîne dans VB.NET.
Facilement convertible en C #:
Public Function GetTempDirectory() As String
Dim mpath As String
Do
mpath = System.IO.Path.Combine(System.IO.Path.GetTempPath, System.IO.Path.GetRandomFileName)
Loop While System.IO.Directory.Exists(mpath) Or System.IO.File.Exists(mpath)
System.IO.Directory.CreateDirectory(mpath)
Return mpath
End Function
C'est un moyen simple mais efficace de générer des noms de fichiers incrémentiels. Il cherchera directement dans le courant (vous pourrez facilement l'indiquer ailleurs) et recherchera des fichiers avec la base YourApplicationName * .txt (encore une fois, vous pourrez facilement changer cela). Il commencera à 0000 pour que le premier nom de fichier soit YourApplicationName0000.txt. Si, pour une raison quelconque, il existe des noms de fichiers avec des fichiers indésirables entre les parties gauche et droite (ce qui ne signifie pas des nombres), ces fichiers seront ignorés en raison de l'appel tryparse.
public static string CreateNewOutPutFile()
{
const string RemoveLeft = "YourApplicationName";
const string RemoveRight = ".txt";
const string searchString = RemoveLeft + "*" + RemoveRight;
const string numberSpecifier = "0000";
int maxTempNdx = -1;
string fileName;
string [] Files = Directory.GetFiles(Directory.GetCurrentDirectory(), searchString);
foreach( string file in Files)
{
fileName = Path.GetFileName(file);
string stripped = fileName.Remove(fileName.Length - RemoveRight.Length, RemoveRight.Length).Remove(0, RemoveLeft.Length);
if( int.TryParse(stripped,out int current) )
{
if (current > maxTempNdx)
maxTempNdx = current;
}
}
maxTempNdx++;
fileName = RemoveLeft + maxTempNdx.ToString(numberSpecifier) + RemoveRight;
File.CreateText(fileName); // optional
return fileName;
}
Sur la base des réponses trouvées sur Internet, je parviens à mon code comme suit:
public static string GetTemporaryFileName()
{
string tempFilePath = Path.Combine(Path.GetTempPath(), "SnapshotTemp");
Directory.Delete(tempFilePath, true);
Directory.CreateDirectory(tempFilePath);
return Path.Combine(tempFilePath, DateTime.Now.ToString("MMddHHmm") + "-" + Guid.NewGuid().ToString() + ".png");
}
Et comme le livre de recettes C # de Jay Hilyard, Stephen Teilhet a indiqué: Utilisation d’un fichier temporaire dans votre application :
vous devez utiliser un fichier temporaire chaque fois que vous avez besoin de stocker temporairement des informations pour les récupérer ultérieurement.
La seule chose dont vous devez vous rappeler est de supprimer ce fichier temporaire avant la fin de l'application qui l'a créé.
S'il n'est pas supprimé, il restera dans le répertoire temporaire de l'utilisateur jusqu'à ce que l'utilisateur le supprime manuellement.
Voici ce que je fais:
string tStamp = String.Format ("{0: yyyyyMMdd.HHmmss}", DateTime.Now); string ProcID = Process.GetCurrentProcess (). Id.ToString (); string tmpFolder = System.IO.Path.GetTempPath (); string outFile = tmpFolder + ProcID + "_" + tStamp + ".txt";