it-swarm.com.de

Wie können Sie leicht überprüfen, ob der Zugriff auf eine Datei in .NET verweigert wird?

Grundsätzlich möchte ich überprüfen, ob ich zum Öffnen der Datei berechtigt bin, bevor ich tatsächlich versuche, sie zu öffnen. Ich möchte für diesen Check keinen Try/Catch verwenden, es sei denn, ich muss. Gibt es eine Dateizugriffseigenschaft, die ich vorher überprüfen kann?

98
Horas

Ich habe dies in der Vergangenheit unzählige Male getan, und fast jedes Mal, wenn ich es getan habe, war es falsch, den Versuch überhaupt zu machen.

Dateiberechtigungen (auch das Vorhandensein von Dateien) sind flüchtig - sie können sich jederzeit ändern. Dank Murphys Gesetz schließt dies besonders den kurzen Zeitraum zwischen dem Überprüfen der Datei und dem Versuch, sie zu öffnen, ein. Eine Änderung ist sogar noch wahrscheinlicher, wenn Sie sich in einem Bereich befinden, von dem Sie wissen, dass Sie dies zuerst überprüfen müssen. Seltsamerweise wird dies jedoch in Ihren Test- oder Entwicklungsumgebungen, die in der Regel relativ statisch sind, niemals vorkommen. Dies macht es schwierig, das Problem später zu finden, und macht es für diese Art von Fehler einfach, es in die Produktion zu schaffen.

Dies bedeutet, dass Sie in der Lage sein müssen, die Ausnahme zu behandeln, wenn die Dateiberechtigungen oder -existenz trotz Ihrer Prüfung schlecht sind. Ausnahmebehandlungscode ist erforderlich, unabhängig davon, ob Sie die Berechtigungen der Datei im Voraus prüfen. Der Code für die Ausnahmebehandlung enthält alle Informationen zur Funktionalität von Existenz- oder Berechtigungsprüfungen. Während Ausnahmebehandlungsroutinen wie diese bekanntermaßen langsam sind, ist es wichtig zu bedenken, dass die Datenträger-E/A noch langsamer ist ... a lot langsamer ... und die Funktion .Exists () oder aufruft Durch das Überprüfen der Berechtigungen wird eine zusätzliche Auslösung des Dateisystems erzwungen.

Zusammenfassend ist eine erste Überprüfung vor dem Versuch, die Datei zu öffnen, sowohl redundant als auch verschwenderisch. Es gibt keinen zusätzlichen Vorteil gegenüber der Ausnahmebehandlung, es wird tatsächlich schaden, nicht helfen, Ihre Leistung, es erhöht die Kosten in Bezug auf mehr Code, der gewartet werden muss, und es kann subtile Fehler in Ihren Code einführen. Es gibt überhaupt keinen Vorteil, die Erstprüfung durchzuführen. Stattdessen ist es hier richtig, einfach zu versuchen, die Datei zu öffnen und sich in eine gute Ausnahmebehandlung zu stecken, wenn sie fehlschlägt. Dies gilt auch dann, wenn Sie nur prüfen, ob die Datei vorhanden ist oder nicht. Diese Argumentation gilt für any volatile resource.

151
Joel Coehoorn

Schneller Tipp für alle, die mit einem ähnlichen Problem hierher kommen:

Achten Sie auf Web-Synchronisierungs-Apps wie DropBox. Ich habe gerade 2 Stunden damit verbracht zu denken, dass die "using" -Anweisung (Dispose-Muster) in .NET fehlerhaft ist.

Schließlich wurde mir klar, dass Dropbox ständig Dateien im Hintergrund liest und schreibt, um sie zu synchronisieren.

Ratet mal, wo sich mein Visual Studio-Projektordner befindet? Natürlich im Ordner "My Dropbox".

Da ich meine Anwendung im Debug-Modus ausführte, wurden die gelesenen und geschriebenen Dateien auch von DropBox kontinuierlich abgerufen, um mit dem DropBox-Server synchronisiert zu werden. Dies führte zu Sperr-/Zugriffskonflikten.

Zumindest weiß ich jetzt, dass ich eine robustere Funktion zum Öffnen von Dateien (z. B. TryOpen (), die mehrere Versuche unternimmt) benötige. Ich bin überrascht, dass es nicht bereits ein fester Bestandteil des Frameworks ist.

[Aktualisieren]

Hier ist meine Hilfsfunktion:

/// <summary>
/// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts.
/// </summary>
/// <param name="filePath">The full file path to be opened</param>
/// <param name="fileMode">Required file mode enum value(see MSDN documentation)</param>
/// <param name="fileAccess">Required file access enum value(see MSDN documentation)</param>
/// <param name="fileShare">Required file share enum value(see MSDN documentation)</param>
/// <param name="maximumAttempts">The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file)</param>
/// <param name="attemptWaitMS">The delay in Milliseconds between each attempt.</param>
/// <returns>A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts</returns>
public FileStream TryOpen(string filePath, FileMode fileMode, FileAccess fileAccess,FileShare fileShare,int maximumAttempts,int attemptWaitMS)
{
    FileStream fs = null;
    int attempts = 0;

    // Loop allow multiple attempts
    while (true)
    {
        try
        {
            fs = File.Open(filePath, fileMode, fileAccess, fileShare);

            //If we get here, the File.Open succeeded, so break out of the loop and return the FileStream
            break;
        }
        catch (IOException ioEx)
        {
            // IOExcception is thrown if the file is in use by another process.

            // Check the numbere of attempts to ensure no infinite loop
            attempts++;
            if (attempts > maximumAttempts)
            {
                // Too many attempts,cannot Open File, break and return null 
                fs = null;
                break;
            }
            else
            {
                // Sleep before making another attempt
                Thread.Sleep(attemptWaitMS);

            }

        }

    }
    // Reutn the filestream, may be valid or null
    return fs;
}
22
Ash

Hier ist die Lösung, die Sie suchen

var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read,
                                            System.Security.AccessControl.AccessControlActions.View,
                                            MyPath);

if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read)
{
    // Do your thing here...
}

dadurch wird eine neue Leseberechtigung basierend auf dem Ansichtspfad aller Dateien erstellt. Anschließend wird überprüft, ob der Lesezugriff auf Dateien identisch ist.

4
dj shahar

Erstens, was Joel Coehoorn gesagt hat.

Außerdem sollten Sie die Annahmen untersuchen, die Ihrem Wunsch zugrunde liegen, die Verwendung von try/catch zu vermeiden, es sei denn, Sie müssen dies tun. Der typische Grund für die Vermeidung von Logik, die von Ausnahmen abhängt (das Erstellen von Exception -Objekten funktioniert schlecht), ist wahrscheinlich nicht relevant für Code, der eine Datei öffnet.

Ich nehme an, wenn Sie eine Methode schreiben, die ein List<FileStream> Wenn Sie jede Datei in einem Verzeichnis-Teilbaum öffnen und davon ausgehen, dass auf eine große Anzahl von Dateien nicht zugegriffen werden kann, möchten Sie möglicherweise die Dateiberechtigungen überprüfen, bevor Sie versuchen, eine Datei zu öffnen, damit Sie nicht zu viele Ausnahmen erhalten. Aber Sie würden immer noch die Ausnahme behandeln. Wahrscheinlich stimmt auch etwas nicht mit dem Design Ihres Programms, wenn Sie eine Methode schreiben, die dies tut.

3
Robert Rossney
public static bool IsFileLocked(string filename)
        {
            bool Locked = false;
            try
            {
                FileStream fs =
                    File.Open(filename, FileMode.OpenOrCreate,
                    FileAccess.ReadWrite, FileShare.None);
                fs.Close();
            }
            catch (IOException ex)
            {
                Locked = true;
            }
            return Locked;
        }
0
Omid Maturi