Frage

Ich arbeite an einem Programm, das mehrere temporäre Ordner für die Anwendung erstellen muss.Diese sind für den Benutzer nicht sichtbar.Die App ist in VB.net geschrieben.Ich kann mir ein paar Möglichkeiten vorstellen, wie zum Beispiel inkrementelle Ordnernamen oder zufällig nummerierte Ordnernamen, aber ich habe mich gefragt, wie andere Leute dieses Problem lösen?

War es hilfreich?

Lösung

Aktualisieren: File.Exists-Prüfung pro Kommentar hinzugefügt (19.06.2012)

Folgendes habe ich in VB.NET verwendet.Im Wesentlichen dasselbe wie dargestellt, außer dass ich den Ordner normalerweise nicht sofort erstellen wollte.

Der Vorteil zu nutzen GetRandomFilename ist, dass keine Datei erstellt wird, sodass Sie nicht bereinigen müssen, wenn Sie den Namen für etwas anderes als eine Datei verwenden.Als würde man es für den Ordnernamen verwenden.

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

Zufällig Beispiel für einen Dateinamen:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen emp\u3z5e0co.tvq


Hier ist eine Variante, die eine Guid verwendet, um den Namen des temporären Ordners zu erhalten.

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

Anleitung Beispiel:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen emp\2dbc6db7-2d45-4b75-b27f-0bd492c60496

Andere Tipps

Sie müssen verwenden System.IO.Path.GetTempFileName()

Erstellt eine temporäre Null-Byte-Datei mit eindeutigem Namen auf der Festplatte und gibt den vollständigen Pfad dieser Datei zurück.

Sie können verwenden System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName()) um nur die Informationen zum temporären Ordner abzurufen und dort Ihre Ordner zu erstellen

Sie werden im temporären Windows-Ordner erstellt und gelten als bewährte Vorgehensweise

Nur um klarzustellen:

System.IO.Path.GetTempPath()

gibt nur den Ordnerpfad zum temporären Ordner zurück.

System.IO.Path.GetTempFileName()

gibt den vollständig qualifizierten Dateinamen (einschließlich Pfad) zurück, also Folgendes:

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

ist überflüssig.

Eine mögliche Rennbedingung liegt vor, wenn:

  • Erstellen einer temporären Datei mit GetTempFileName(), löschen und einen Ordner mit demselben Namen erstellen, oder
  • verwenden GetRandomFileName() oder Guid.NewGuid.ToString um einen Ordner zu benennen und den Ordner später zu erstellen

Mit GetTempFileName() Nach dem Löschvorgang könnte eine andere Anwendung erfolgreich eine temporäre Datei mit demselben Namen erstellen.Der CreateDirectory() würde dann scheitern.

Ebenso zwischen Anrufen GetRandomFileName() und beim Erstellen des Verzeichnisses könnte ein anderer Prozess eine Datei oder ein Verzeichnis mit demselben Namen erstellen, was wiederum dazu führt CreateDirectory() Versagen.

Bei den meisten Anwendungen ist es in Ordnung, dass ein temporäres Verzeichnis aufgrund einer Race-Bedingung fehlschlägt.Es ist schließlich äußerst selten.Für sie können diese Rennen oft ignoriert werden.

In der Welt der Unix-Shell-Skripte ist die sichere und rennfreie Erstellung temporärer Dateien und Verzeichnisse eine große Sache.Viele Maschinen haben mehrere (feindliche) Benutzer – man denke an einen gemeinsam genutzten Webhost – und viele Skripte und Anwendungen müssen temporäre Dateien und Verzeichnisse sicher im gemeinsam genutzten /tmp-Verzeichnis erstellen.Sehen Temporäre Dateien in Shell-Skripten sicher erstellen für eine Diskussion darüber, wie man temporäre Verzeichnisse sicher aus Shell-Skripten erstellt.

Als @JonathanWright wies darauf hin, Für die Lösungen gelten Rennbedingungen:

  • Erstellen Sie eine temporäre Datei mit GetTempFileName(), löschen Sie es und erstellen Sie einen Ordner mit demselben Namen
  • Verwenden GetRandomFileName() oder Guid.NewGuid.ToString Um einen zufälligen Ordnernamen zu erstellen, prüfen Sie, ob er existiert, und erstellen Sie ihn, wenn nicht.

Es ist jedoch möglich, mithilfe von atomar ein eindeutiges temporäres Verzeichnis zu erstellen Transaktionales NTFS (TxF)-API.

TxF hat eine CreateDirectoryTransacted() Funktion, die über Platform Invoke aufgerufen werden kann.Dazu habe ich mich angepasst Mohammad Elsheimys Code für den Anruf 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());
}

Etwas wie...

using System.IO;

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

Directory.CreateDirectory(path);

Sie könnten eine GUID für Ihre temporären Ordnernamen generieren.

Solange der Name des Ordners nicht aussagekräftig sein muss, wie wäre es dann mit der Verwendung einer GUID dafür?

Sie können verwenden GetTempFileName um ein Provisorium zu erstellen Datei, löschen Sie dann diese Datei und erstellen Sie sie stattdessen als Verzeichnis neu.

Notiz:Link hat nicht funktioniert, kopieren/einfügen von: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

Kombinierte Antworten von @adam-wright und pix0r funktionieren meiner Meinung nach am besten:


using System.IO;

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

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

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

Der Vorteil der Verwendung von System.IO.Path.GetTempFileName besteht darin, dass es sich um eine Datei im lokalen (d. h. nicht-roamingfähigen) Pfad des Benutzers handelt.Genau an dieser Stelle würden Sie es aus Berechtigungs- und Sicherheitsgründen haben wollen.

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

@JonathanWright schlägt vor, dass CreateDirectory fehlschlägt, wenn bereits ein Ordner vorhanden ist.Wenn ich Directory.CreateDirectory lese, heißt es: 'Dieses Objekt wird zurückgegeben, unabhängig davon, ob ein Verzeichnis unter dem angegebenen Pfad bereits vorhanden ist.' Das bedeutet, dass Sie keinen Ordner erkennen, der zwischen der Prüfung und der tatsächlichen Erstellung erstellt wurde.

Mir gefällt die von @DanielTrebbien vorgeschlagene Funktion „CreateDirectoryTransacted()“, aber diese Funktion ist veraltet.

Die einzige Lösung, die ich sehe, besteht darin, die CAP-API zu verwenden und „Verzeichnis erstellen' gibt es einen Fehler, wenn der Ordner vorhanden ist, wenn Sie wirklich sicherstellen müssen, dass die gesamte Rennbedingung abgedeckt ist.Das würde in etwa so aussehen:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top