2008-11-10 19 views
84

Was ist der beste Weg, um einen temporären Verzeichnisnamen in Windows zu bekommen? Ich sehe, dass ich GetTempPath und GetTempFileName verwenden kann, um eine temporäre Datei zu erstellen, aber ist es gleichwertig mit der Linux/BSD mkdtemp Funktion zum Erstellen eines temporären Verzeichnisses?Erstellen eines temporären Verzeichnisses in Windows?

+0

Diese Frage scheint ein wenig schwer zu finden. Insbesondere wird es nicht angezeigt, wenn Sie im Stack Overflow-Suchfeld beispielsweise "temp-Verzeichnis .net" eingeben. Das scheint bedauerlich, da die Antworten bisher alle .NET-Antworten sind. Denkst du, du könntest das ".net" -Tag hinzufügen? (Und vielleicht das "directory" oder "temporary-directory" -Tag?) Oder vielleicht das Wort ".NET" zum Titel hinzufügen? Vielleicht auch in der Frage Körper abwechselnd sagen "temp" mit "temporären" - wenn Sie also nach der kürzeren Form suchen, erhalten Sie immer noch eine gute Übereinstimmung der Textsuche. Ich habe nicht genug Repräsenz, um diese Dinge selbst zu machen. Danke. – Chris

+0

Nun, ich war auf der Suche nach einer Nicht-.NET-Antwort, also würde ich das lieber weglassen, aber ich habe die anderen Änderungen vorgenommen, die Sie vorgeschlagen haben. Vielen Dank. –

+0

@Josh Kelley: Ich habe nur die Win32-API überprüft, und die einzigen Möglichkeiten bestehen darin, einen ähnlichen Ansatz zum Abrufen des Temp-Pfads, zum Generieren eines Ramdom-Dateinamens und zum anschließenden Erstellen eines Verzeichnisses zu verwenden. –

Antwort

165

Nein, es gibt kein Äquivalent zu mkdtemp. Die beste Option ist eine Kombination aus GetTempPath und GetRandomFileName.

Sie würden Code ähnlich wie diese benötigen:

public string GetTemporaryDirectory() 
{ 
    string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 
    Directory.CreateDirectory(tempDirectory); 
    return tempDirectory; 
} 
+0

@Will: Danke für die Bearbeitung und Korrektur meines Tippfehlers! Ein zu viele Kopier-/Einfügefehler. :( –

+3

Dies scheint ein wenig gefährlich. Insbesondere gibt es eine Chance (klein, aber nicht Null, oder?), Dass Path.Combine (Path.GetTempPath(), Path.GetRandomFileName()) den Namen eines Verzeichnisses zurückgibt Dies ist bereits vorhanden. Da Directory.CreateDirectory (tempDirectory) keine Ausnahme auslöst, wenn tempDirectory bereits vorhanden ist, wird dieser Fall von Ihrer Anwendung nicht erkannt. Und dann haben Sie möglicherweise zwei Anwendungen, die auf die Arbeit des jeweils anderen treten. Gibt es eine sicherere Alternative in .NET? – Chris

+19

@Chris: Die GetRandomFileName-Methode gibt eine kryptografisch starke, zufällige Zeichenfolge zurück, die entweder als Ordnername oder als Dateiname verwendet werden kann.Es ist theoretisch möglich, dass der resultierende Pfad bereits existieren könnte, aber dort Sie können überprüfen, ob der Pfad vorhanden ist, und ob er Path.GetRandomFileName() erneut aufruft, und wiederholen Sie das. –

1

GetTempPath ist der richtige Weg es zu tun; Ich bin mir nicht sicher, was Sie an dieser Methode interessiert. Sie können dann CreateDirectory verwenden, um es zu machen.

+0

Ein Problem ist, dass GetTempFileName eine Null-Byte-Datei erstellen wird. Sie müssen stattdessen GetTempPath, GetRandomFileName und CreateDirectory verwenden. –

+0

Was ist in Ordnung, möglich und machbar. Ich wollte Code bereitstellen, aber Dorman hat es mir vor Augen geführt, und es funktioniert einwandfrei. – Will

0

Wie oben erwähnt, Path.GetTempPath() ist eine Möglichkeit, es zu tun. Sie können auch Environment.GetEnvironmentVariable("TEMP") aufrufen, wenn der Benutzer eine TEMP-Umgebungsvariable eingerichtet hat.

Wenn Sie sich mit dem temporären Verzeichnis als Mittel plane Daten in der Anwendung von persistierenden, werden Sie wahrscheinlich bei Verwendung IsolatedStorage als Repository für die Konfiguration/Zustand aussehen sollten/etc ...

7

Ich mag verwenden GetTempPath(), eine GUID-Erstellungsfunktion wie CoCreateGuid() und CreateDirectory().

Eine GUID wurde entwickelt, um eine hohe Wahrscheinlichkeit der Eindeutigkeit zu haben, und es ist auch sehr unwahrscheinlich, dass jemand manuell ein Verzeichnis mit der gleichen Form wie eine GUID erstellen würde (und wenn CreateDirectory() CreateDirectory() wird fehlschlagen, seine Existenz anzuzeigen).)

16

Ich hack Path.GetTempFileName(), um mir einen gültigen, pseudozufälligen Dateipfad auf der Festplatte, dann löschen Sie die Datei, und erstellen Sie ein Verzeichnis mit dem gleichen Dateipfad.

Dies vermeidet die Notwendigkeit zur Überprüfung, ob der Dateipfad in einer Weile oder Schleife verfügbar ist, per Chris' Kommentar zu Scott Dorman Antwort.

public string GetTemporaryDirectory() 
{ 
    string tempFolder = Path.GetTempFileName(); 
    File.Delete(tempFolder); 
    Directory.CreateDirectory(tempFolder); 

    return tempFolder; 
} 

Wenn Sie wirklich ein kryptografisch sicheren Zufallsnamen benötigen, können Sie wollen Scotts Antwort anzupassen eine Weile zu verwenden oder eine Schleife tun, um immer wieder versuchen, einen Pfad auf der Festplatte zu erstellen.

+0

Das ist ein netter kleiner Trick! – JMS10

1

Hier ist ein etwas bruteter Ansatz zur Lösung des Kollisionsproblems für temporäre Verzeichnisnamen. Es ist kein unfehlbarer Ansatz, aber es reduziert die Wahrscheinlichkeit einer Ordnerpfadkollision erheblich.

Man könnte möglicherweise andere Verfahren hinzufügen oder Montagebezogene Informationen zu den Verzeichnisnamen der Kollision noch weniger wahrscheinlich zu machen, obwohl eine solche Informationen sichtbar auf dem temporären Verzeichnis Namen machen könnte nicht wünschenswert sein. Man könnte auch die Reihenfolge mischen, mit der die zeitbezogenen Felder kombiniert werden, damit die Ordnernamen zufälliger aussehen. Ich persönlich bevorzuge es, es einfach so zu belassen, weil es für mich einfacher ist, sie alle während des Debuggens zu finden.

string randomlyGeneratedFolderNamePart = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); 

string timeRelatedFolderNamePart = DateTime.Now.Year.ToString() 
           + DateTime.Now.Month.ToString() 
           + DateTime.Now.Day.ToString() 
           + DateTime.Now.Hour.ToString() 
           + DateTime.Now.Minute.ToString() 
           + DateTime.Now.Second.ToString() 
           + DateTime.Now.Millisecond.ToString(); 

string processRelatedFolderNamePart = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); 

string temporaryDirectoryName = Path.Combine(Path.GetTempPath() 
              , timeRelatedFolderNamePart 
              + processRelatedFolderNamePart 
              + randomlyGeneratedFolderNamePart); 
2

@Chris. Auch ich war besessen von dem Risiko, dass ein temporäres Verzeichnis bereits existiert. Die Diskussionen über Zufall und kryptographisch stark befriedigen mich auch nicht vollständig.

Mein Ansatz baut auf der grundlegenden Tatsache, dass die O/S muss 2 Anrufe, eine Datei erstellen beiden Erfolge haben nicht zulassen. Es ist ein wenig überraschend, dass.NET-Designer haben sich entschieden, die Win32-API-Funktionalität für Verzeichnisse zu verbergen, was dies viel einfacher macht, da es einen Fehler zurückgibt, wenn Sie versuchen, ein Verzeichnis zum zweiten Mal zu erstellen. Hier ist, was ich benutze:

[DllImport(@"kernel32.dll", EntryPoint = "CreateDirectory", SetLastError = true, CharSet = CharSet.Unicode)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool CreateDirectoryApi 
     ([MarshalAs(UnmanagedType.LPTStr)] string lpPathName, IntPtr lpSecurityAttributes); 

    /// <summary> 
    /// Creates the directory if it does not exist. 
    /// </summary> 
    /// <param name="directoryPath">The directory path.</param> 
    /// <returns>Returns false if directory already exists. Exceptions for any other errors</returns> 
    /// <exception cref="System.ComponentModel.Win32Exception"></exception> 
    internal static bool CreateDirectoryIfItDoesNotExist([NotNull] string directoryPath) 
    { 
     if (directoryPath == null) throw new ArgumentNullException("directoryPath"); 

     // First ensure parent exists, since the WIN Api does not 
     CreateParentFolder(directoryPath); 

     if (!CreateDirectoryApi(directoryPath, lpSecurityAttributes: IntPtr.Zero)) 
     { 
      Win32Exception lastException = new Win32Exception(); 

      const int ERROR_ALREADY_EXISTS = 183; 
      if (lastException.NativeErrorCode == ERROR_ALREADY_EXISTS) return false; 

      throw new System.IO.IOException(
       "An exception occurred while creating directory'" + directoryPath + "'".NewLine() + lastException); 
     } 

     return true; 
    } 

Sie erhalten zu entscheiden, ob die „Kosten/Risiko“ von nicht verwalteten p/aufrufen Code ist es wert. Die meisten würden sagen, dass es nicht so ist, aber zumindest haben Sie jetzt die Wahl.

CreateParentFolder() wird dem Schüler als Übung überlassen. Ich benutze Directory.CreateDirectory(). Achten Sie darauf, das übergeordnete Element eines Verzeichnisses zu erhalten, da es im Stammverzeichnis null ist.

0

ich dies in der Regel verwenden:

/// <summary> 
    /// Creates the unique temporary directory. 
    /// </summary> 
    /// <returns> 
    /// Directory path. 
    /// </returns> 
    public string CreateUniqueTempDirectory() 
    { 
     var uniqueTempDir = Path.GetFullPath(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())); 
     Directory.CreateDirectory(uniqueTempDir); 
     return uniqueTempDir; 
    } 

Wenn Sie absolut sicher sein wollen, dass diese Verzeichnisname wird nicht in temporären Pfad vorhanden ist, dann müssen Sie überprüfen, ob dieses einzigartige Verzeichnisname existiert und versuchen, andere zu erstellen wenn es wirklich existiert.

Aber diese GUID-basierte Implementierung ist ausreichend. Ich habe keine Erfahrung mit irgendeinem Problem in diesem Fall. Einige MS-Anwendungen verwenden auch GUID-basierte temporäre Verzeichnisse.

Verwandte Themen