987 Stimmen

Gibt es eine Möglichkeit zu überprüfen, ob eine Datei in Gebrauch ist?

Ich schreibe ein Programm in C#, das wiederholt auf 1 Bilddatei zugreifen muss. Die meiste Zeit funktioniert es, aber wenn mein Computer schnell läuft, wird es versuchen, auf die Datei zuzugreifen, bevor es zurück in das Dateisystem gespeichert wurde und einen Fehler ausgeben:

"Datei wird von einem anderen Prozess verwendet"

Ich würde gerne einen Weg finden, dies zu umgehen, aber alles, was ich gegoogelt habe, hat nur die Erstellung von Prüfungen mit Hilfe der Ausnahmebehandlung ergeben. Dies ist gegen meine Religion, so ich frage mich, ob jemand einen besseren Weg, es zu tun hat?

35 Stimmen

Sie können dies testen, indem Sie alle offenen Handles auf dem System untersuchen. Da es sich bei Windows jedoch um ein Multitasking-Betriebssystem handelt, besteht die Möglichkeit, dass direkt nach der Ausführung des Codes, mit dem festgestellt werden soll, ob die Datei geöffnet ist, ein Prozesscode mit der Verwendung dieser Datei beginnt und zu dem Zeitpunkt, zu dem Sie versuchen, sie zu verwenden, ein Fehler auftritt. Es ist jedoch nicht verkehrt, zuerst zu prüfen, ob die Datei geöffnet ist; gehen Sie nur nicht davon aus, dass sie nicht verwendet wird, wenn Sie sie tatsächlich benötigen.

6 Stimmen

Aber gerade für dieses spezielle Problem würde ich empfehlen, die Dateihandles nicht zu untersuchen und nur eine bestimmte Anzahl von Versuchen durchzuführen, z. B. 3-5, bevor sie fehlschlagen.

0 Stimmen

Wie wird diese Bilddatei erstellt? Können Sie Ihr Programm anhalten/schlafen/pausieren, bis die Erzeugung abgeschlossen ist? Das ist bei weitem der bessere Weg, um die Situation zu bewältigen. Wenn nicht, dann glaube ich nicht, dass Sie eine Ausnahmebehandlung vermeiden können.

7voto

rboy Punkte 1747

Die oben akzeptierten Antworten weisen ein Problem auf, bei dem der Code nicht funktioniert, wenn die Datei zum Schreiben mit einem FileShare.Read-Modus geöffnet wurde oder wenn die Datei ein Read-Only-Attribut hat. Diese modifizierte Lösung funktioniert am zuverlässigsten, wobei zwei Dinge zu beachten sind (die auch für die akzeptierte Lösung gelten):

  1. Es funktioniert nicht für Dateien, die mit einem Schreibfreigabemodus geöffnet wurden
  2. Dabei werden Threading-Probleme nicht berücksichtigt, so dass Sie es sperren oder Threading-Probleme separat behandeln müssen.

Unter Berücksichtigung der obigen Ausführungen wird geprüft, ob die Datei entweder zum Schreiben gesperrt o gesperrt, um das Lesen zu verhindern :

public static bool FileLocked(string FileName)
{
    FileStream fs = null;

    try
    {
        // NOTE: This doesn't handle situations where file is opened for writing by another process but put into write shared mode, it will not throw an exception and won't show it as write locked
        fs = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // If we can't open file for reading and writing then it's locked by another process for writing
    }
    catch (UnauthorizedAccessException) // https://msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx
    {
        // This is because the file is Read-Only and we tried to open in ReadWrite mode, now try to open in Read only mode
        try
        {
            fs = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);
        }
        catch (Exception)
        {
            return true; // This file has been locked, we can't even open it to read
        }
    }
    catch (Exception)
    {
        return true; // This file has been locked
    }
    finally
    {
        if (fs != null)
            fs.Close();
    }
    return false;
}

7voto

Ivan Branets Punkte 594

Sie können eine Aufgabe zurückgeben, die Ihnen einen Stream liefert, sobald dieser verfügbar ist. Das ist eine vereinfachte Lösung, aber ein guter Ausgangspunkt. Sie ist thread-sicher.

private async Task<Stream> GetStreamAsync()
{
    try
    {
        return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
    }
    catch (IOException)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return await GetStreamAsync();
    }
}

Sie können diesen Stream wie gewohnt nutzen:

using (var stream = await FileStreamGetter.GetStreamAsync())
{
    Console.WriteLine(stream.Length);
}

6voto

Karl Johan Punkte 3832

Vielleicht könnten Sie eine FileSystemWatcher und achten Sie auf das Ereignis "Changed".

Ich habe es selbst noch nicht verwendet, aber es könnte einen Versuch wert sein. Wenn sich der Filesystemwatcher als zu schwer für diesen Fall erweist, würde ich die try/catch/sleep-Schleife verwenden.

5voto

Julian Punkte 97
static bool FileInUse(string path)
    {
        try
        {
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            {
                fs.CanWrite
            }
            return false;
        }
        catch (IOException ex)
        {
            return true;
        }
    }

string filePath = "C:\\Documents And Settings\\yourfilename";
bool isFileInUse;

isFileInUse = FileInUse(filePath);

// Then you can do some checking
if (isFileInUse)
   Console.WriteLine("File is in use");
else
   Console.WriteLine("File is not in use");

Ich hoffe, das hilft!

5voto

cdiggins Punkte 16400

Hier ist ein Code, der, soweit ich das beurteilen kann, das Gleiche tut wie die akzeptierte Antwort, aber mit weniger Code:

    public static bool IsFileLocked(string file)
    {
        try
        {
            using (var stream = File.OpenRead(file))
                return false;
        }
        catch (IOException)
        {
            return true;
        }        
    }

Ich denke jedoch, dass es robuster ist, dies auf folgende Weise zu tun:

    public static void TryToDoWithFileStream(string file, Action<FileStream> action, 
        int count, int msecTimeOut)
    {
        FileStream stream = null;
        for (var i = 0; i < count; ++i)
        {
            try
            {
                stream = File.OpenRead(file);
                break;
            }
            catch (IOException)
            {
                Thread.Sleep(msecTimeOut);
            }
        }
        action(stream);
    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X