web-dev-qa-db-fra.com

Comment créer un fichier temporaire avec une extension spécifique avec .NET?

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.

255
Brann

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.

328
Mitch Wheat

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.

52
JaredPar
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 ();

41
Maxence

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.

18
Mehmet Aras

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));
9
Matías

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 .

8
Colonel Panic

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.

6
I.R.Baboon

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");
5
Michael Prewecki

Fonction facile en C #:

public static string GetTempFileName(string extension = "csv")
{
    return Path.ChangeExtension(Path.GetTempFileName(), extension);
}
3
RanchMobile

À 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

  • Unique
  • Sans conflit (n'existe pas déjà)
  • Atomic (Création d'un nom et d'un fichier dans la même opération)
  • Difficile à deviner

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);
3
Daniel C. Oderbolz

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
2
Paolo Iommarini

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
2
Simon

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;
    }
0
Display name

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.

0
Speedoops

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"; 
0