Ich schreibe ein Programm in C #, das wiederholt auf 1 Bilddatei zugreifen muss. Meistens funktioniert es, aber wenn mein Computer schnell läuft, versucht er, auf die Datei zuzugreifen, bevor sie wieder im Dateisystem gespeichert wurde, und gibt den Fehler "Datei wird von einem anderen Prozess verwendet" aus .
Ich würde gerne einen Weg finden, um dies zu umgehen, aber mein ganzes Googeln hat nur dazu geführt, dass Schecks mithilfe der Ausnahmebehandlung erstellt wurden. Das ist gegen meine Religion, also habe ich mich gefragt, ob jemand einen besseren Weg hat, es zu tun?
Antworten:
Aktualisiert HINWEIS zu dieser Lösung : Die Überprüfung mit
FileAccess.ReadWrite
schlägt bei schreibgeschützten Dateien fehl, sodass die Lösung für die Überprüfung geändert wurdeFileAccess.Read
. Diese Lösung funktioniert zwar, da der Versuch, mit zu prüfenFileAccess.Read
, fehlschlägt, wenn die Datei über eine Schreib- oder Lesesperre verfügt. Diese Lösung funktioniert jedoch nicht, wenn die Datei keine Schreib- oder Lesesperre aufweist, dh geöffnet wurde (zum Lesen oder Schreiben) mit FileShare.Read- oder FileShare.Write-Zugriff.ORIGINAL: Ich habe diesen Code in den letzten Jahren verwendet und hatte keine Probleme damit.
Verstehen Sie Ihr Zögern bei der Verwendung von Ausnahmen, aber Sie können sie nicht immer vermeiden:
quelle
public static bool IsLocked(this FileInfo file) {/*...*/}
.Sie können unter einer Thread-Race-Bedingung leiden, für die es dokumentierte Beispiele gibt, die als Sicherheitslücke verwendet werden. Wenn Sie überprüfen, ob die Datei verfügbar ist, aber dann versuchen, sie zu verwenden, können Sie an dieser Stelle einen Fehler auslösen, den ein böswilliger Benutzer verwenden könnte, um Ihren Code zu erzwingen und auszunutzen.
Ihre beste Wette ist ein try catch / finally, der versucht, das Dateihandle zu erhalten.
quelle
Verwenden Sie diese Option, um zu überprüfen, ob eine Datei gesperrt ist:
Aus Leistungsgründen empfehle ich, den Dateiinhalt im selben Vorgang zu lesen. Hier sind einige Beispiele:
Probieren Sie es selbst aus:
quelle
IOException
, nicht allgemeinException
und dann ein Typentest.IOException
nach dem allgemeinen. Der Allgemeine wird alles fangen, was vorbeigeht, und der SpezifischeIOException
wird immer einsam sein. Tauschen Sie einfach die beiden aus.Verwenden Sie einfach die Ausnahme wie vorgesehen. Akzeptieren Sie, dass die Datei verwendet wird, und versuchen Sie es wiederholt, bis Ihre Aktion abgeschlossen ist. Dies ist auch am effizientesten, da Sie keine Zyklen damit verschwenden, den Status zu überprüfen, bevor Sie handeln.
Verwenden Sie zum Beispiel die folgende Funktion
Wiederverwendbare Methode, die nach 2 Sekunden abläuft
quelle
Vielleicht könnten Sie einen FileSystemWatcher verwenden und auf das geänderte Ereignis achten.
Ich habe das selbst nicht benutzt, aber es könnte einen Versuch wert sein. Wenn sich herausstellt, dass der Dateisystemwatcher in diesem Fall etwas schwer ist, würde ich mich für die try / catch / sleep-Schleife entscheiden.
quelle
Sie können eine Aufgabe zurückgeben, die Ihnen einen Stream gibt, sobald dieser verfügbar ist. Es ist eine vereinfachte Lösung, aber ein guter Ausgangspunkt. Es ist threadsicher.
Sie können diesen Stream wie gewohnt verwenden:
quelle
GetStreamAsync()
?Die einzige mir bekannte Möglichkeit ist die Verwendung der exklusiven Win32-Sperr-API, die nicht zu schnell ist, aber es gibt Beispiele.
Die meisten Menschen versuchen für eine einfache Lösung einfach, Schleifen zu fangen / zu fangen / zu schlafen.
quelle
Hoffe das hilft!
quelle
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 schreibgeschütztes Attribut hat. Diese modifizierte Lösung funktioniert am zuverlässigsten, wobei zwei Dinge zu beachten sind (wie dies auch für die akzeptierte Lösung gilt):
Unter Berücksichtigung der obigen Punkte wird überprüft, ob die Datei entweder zum Schreiben gesperrt oder gesperrt ist, um das Lesen zu verhindern :
quelle
Abgesehen von der Arbeit mit 3-Linern und nur als Referenz: Wenn Sie die vollständigen Informationen wünschen, gibt es ein kleines Projekt im Microsoft Dev Center:
https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4
Aus der Einleitung:
Es funktioniert durch Herstellen einer Verbindung mit der "Restart Manager Session".
Es könnte ein wenig überarbeitet für Ihre speziellen Bedürfnisse sein ... Aber wenn es das ist, was Sie wollen, gehen Sie voran und greifen Sie zum vs-Projekt.
quelle
Nach meiner Erfahrung möchten Sie dies normalerweise tun, dann Ihre Dateien "schützen", um etwas Besonderes zu tun, und dann die "geschützten" Dateien verwenden. Wenn Sie nur eine Datei haben, die Sie so verwenden möchten, können Sie den Trick verwenden, der in der Antwort von Jeremy Thompson erläutert wird. Wenn Sie jedoch versuchen, dies für viele Dateien zu tun (z. B. wenn Sie ein Installationsprogramm schreiben), werden Sie ziemlich verletzt.
Eine sehr elegante Möglichkeit, dies zu lösen, besteht darin, dass Sie in Ihrem Dateisystem keinen Ordnernamen ändern können, wenn eine der Dateien dort verwendet wird. Behalten Sie den Ordner im selben Dateisystem und es wird wie ein Zauber funktionieren.
Beachten Sie, dass Sie sich der offensichtlichen Möglichkeiten bewusst sein sollten, wie dies ausgenutzt werden kann. Schließlich werden die Dateien nicht gesperrt. Beachten Sie auch, dass es andere Gründe gibt, die dazu führen können, dass Ihr
Move
Vorgang fehlschlägt. Offensichtlich kann hier eine ordnungsgemäße Fehlerbehandlung (MSDN) hilfreich sein.Für einzelne Dateien würde ich mich an den Sperrvorschlag von Jeremy Thompson halten.
quelle
FileShare
und Überprüfung auf ein Schloss.Hier ist ein Code, der, soweit ich das am besten beurteilen kann, dasselbe tut wie die akzeptierte Antwort, jedoch mit weniger Code:
Ich denke jedoch, dass es robuster ist, dies auf folgende Weise zu tun:
quelle
Sie können meine Bibliothek für den Zugriff auf Dateien aus mehreren Apps verwenden.
Sie können es von nuget installieren: Install-Package Xabe.FileLock
Wenn Sie weitere Informationen dazu wünschen, besuchen Sie https://github.com/tomaszzmuda/Xabe.FileLock
Die Methode fileLock.Acquire gibt nur dann true zurück, wenn die für dieses Objekt exklusive Datei gesperrt werden kann. Aber App, welche Datei hochladen muss, muss es auch in der Dateisperre tun. Wenn auf das Objekt nicht zugegriffen werden kann, gibt metod false zurück.
quelle
Ich musste einmal PDFs in ein Online-Backup-Archiv hochladen. Die Sicherung schlägt jedoch fehl, wenn der Benutzer die Datei in einem anderen Programm (z. B. einem PDF-Reader) geöffnet hat. In meiner Eile habe ich versucht, einige der wichtigsten Antworten in diesem Thread zu finden, konnte sie jedoch nicht zum Laufen bringen. Was für mich funktioniert hat, war der Versuch, die PDF-Datei in ein eigenes Verzeichnis zu verschieben . Ich stellte fest, dass dies fehlschlagen würde, wenn die Datei in einem anderen Programm geöffnet wäre, und wenn die Verschiebung erfolgreich wäre, wäre kein Wiederherstellungsvorgang erforderlich, wie dies der Fall wäre, wenn sie in ein separates Verzeichnis verschoben würde. Ich möchte meine Basislösung veröffentlichen, falls sie für bestimmte Anwendungsfälle anderer nützlich sein kann.
quelle
Ich bin gespannt, ob dies WTF-Reflexe auslöst. Ich habe einen Prozess, der ein PDF-Dokument über eine Konsolen-App erstellt und anschließend startet. Ich hatte es jedoch mit einer Schwachstelle zu tun, bei der die App eine Ausnahme auslöste und starb, wenn der Benutzer den Prozess mehrmals ausführen und dieselbe Datei generieren würde, ohne zuvor die zuvor generierte Datei zu schließen. Dies kam häufig vor, da Dateinamen auf Angebotsnummern basieren.
Anstatt auf solch unanständige Weise zu scheitern, habe ich mich für die automatisch inkrementierte Dateiversionierung entschieden:
Wahrscheinlich kann dem
catch
Block etwas mehr Sorgfalt gewidmet werden, um sicherzustellen, dass ich die richtigen IOException (s) abfange. Ich werde wahrscheinlich auch den App-Speicher beim Start löschen, da diese Dateien sowieso nur vorübergehend sein sollen.Mir ist klar, dass dies über den Rahmen der Frage des OP hinausgeht, einfach zu überprüfen, ob die Datei verwendet wird, aber dies war tatsächlich das Problem, das ich lösen wollte, als ich hier ankam, sodass es vielleicht für jemand anderen nützlich sein wird.
quelle
Würde so etwas helfen?
quelle
Versuchen Sie, die Datei in ein temporäres Verzeichnis zu verschieben / kopieren. Wenn Sie können, hat es keine Sperre und Sie können sicher im temporären Verzeichnis arbeiten, ohne Sperren zu bekommen. Andernfalls versuchen Sie einfach, es in x Sekunden erneut zu verschieben.
quelle
Ich benutze diese Problemumgehung, aber ich habe eine Zeitspanne zwischen dem Überprüfen der Dateisperrung mit der IsFileLocked-Funktion und dem Öffnen der Datei. In dieser Zeitspanne kann ein anderer Thread die Datei öffnen, sodass ich eine IOException erhalte.
Also habe ich zusätzlichen Code dafür hinzugefügt. In meinem Fall möchte ich XDocument laden:
Was denken Sie? Kann ich etwas ändern? Vielleicht musste ich die IsFileBeingUsed-Funktion überhaupt nicht verwenden?
Vielen Dank
quelle