Was ist der einfachste Weg, einen Thread zu blockieren, bis eine Datei entsperrt wurde und zum Lesen und Umbenennen zugänglich ist? Gibt es beispielsweise irgendwo in .NET Framework ein WaitOnFile ()?
Ich habe einen Dienst, der einen FileSystemWatcher verwendet, um nach Dateien zu suchen, die an eine FTP-Site übertragen werden sollen. Das Ereignis " Datei erstellt" wird jedoch ausgelöst, bevor der andere Prozess das Schreiben der Datei abgeschlossen hat.
Die ideale Lösung hätte eine Zeitüberschreitung, damit der Thread nicht für immer hängt, bevor er aufgibt.
Bearbeiten: Nachdem ich einige der folgenden Lösungen ausprobiert hatte, änderte ich das System so, dass alle Dateien darauf geschrieben wurden, Path.GetTempFileName()
und führte dann eine File.Move()
bis zum endgültigen Speicherort durch. Sobald das FileSystemWatcher
Ereignis ausgelöst wurde, war die Datei bereits vollständig.
Antworten:
Dies war die Antwort, die ich auf eine verwandte Frage gab :
quelle
Ausgehend von Erics Antwort habe ich einige Verbesserungen vorgenommen, um den Code weitaus kompakter und wiederverwendbarer zu machen. Hoffe es ist nützlich.
quelle
using
eine Null zu verwenden. Überprüfen Sie einfach denusing
Block auf Null .fs
imcatch
Block nicht null sein ? Wenn derFileStream
Konstruktor auslöst, wird der Variablen kein Wert zugewiesen, und es gibt nichts anderes in dertry
, das einen auslösen kannIOException
. Mir scheint, es sollte in Ordnung sein, es einfach zu tunreturn new FileStream(...)
.Hier ist ein generischer Code, um dies zu tun, unabhängig von der Dateioperation selbst. Dies ist ein Beispiel für die Verwendung:
oder
Sie können auch die Anzahl der Wiederholungen und die Wartezeit zwischen den Wiederholungen definieren.
HINWEIS: Leider ist der zugrunde liegende Win32-Fehler (ERROR_SHARING_VIOLATION) in .NET nicht verfügbar. Daher habe ich eine kleine Hack-Funktion (
IsSharingViolation
) hinzugefügt, die auf Reflexionsmechanismen basiert, um dies zu überprüfen.quelle
SharingViolationException
. Tatsächlich können sie immer noch abwärtskompatibel sein, solange es abstammtIOException
. Und sie sollten es wirklich, wirklich.Starting with the .NET Framework 4.5, the HResult property's setter is protected, whereas its getter is public. In previous versions of the .NET Framework, both getter and setter are protected.
Ich habe eine Helferklasse für solche Dinge zusammengestellt. Es funktioniert, wenn Sie die Kontrolle über alles haben, was auf die Datei zugreifen würde. Wenn Sie Streit von einer Reihe anderer Dinge erwarten, dann ist dies ziemlich wertlos.
Es funktioniert mit einem benannten Mutex. Diejenigen, die auf die Datei zugreifen möchten, versuchen, die Kontrolle über den benannten Mutex zu erlangen, der den Namen der Datei teilt (wobei die '\' in '/' umgewandelt werden). Sie können entweder Open () verwenden, das blockiert, bis auf den Mutex zugegriffen werden kann, oder TryOpen (TimeSpan), das versucht, den Mutex für die angegebene Dauer abzurufen und false zurückgibt, wenn er nicht innerhalb der Zeitspanne erfasst werden kann. Dies sollte höchstwahrscheinlich in einem using-Block verwendet werden, um sicherzustellen, dass Sperren ordnungsgemäß freigegeben werden und der Stream (falls geöffnet) ordnungsgemäß entsorgt wird, wenn dieses Objekt entsorgt wird.
Ich habe einen kurzen Test mit ~ 20 Dingen durchgeführt, um verschiedene Lese- / Schreibvorgänge für die Datei durchzuführen, und keine Korruption festgestellt. Natürlich ist es nicht sehr weit fortgeschritten, aber es sollte für die meisten einfachen Fälle funktionieren.
quelle
Bei dieser speziellen Anwendung führt das direkte Beobachten der Datei unweigerlich zu einem schwer zu verfolgenden Fehler, insbesondere wenn die Dateigröße zunimmt. Hier sind zwei verschiedene Strategien, die funktionieren werden.
Viel Glück!
quelle
Eine der Techniken, die ich vor einiger Zeit verwendet habe, war das Schreiben meiner eigenen Funktion. Fangen Sie die Ausnahme ab und versuchen Sie es erneut mit einem Timer, den Sie für eine bestimmte Dauer auslösen können. Wenn es einen besseren Weg gibt, teilen Sie ihn bitte mit.
quelle
Von MSDN :
Ihr FileSystemWatcher kann so geändert werden, dass er während des Ereignisses "OnCreated" nicht gelesen / umbenannt wird, sondern:
quelle
In den meisten Fällen funktioniert ein einfacher Ansatz wie der von @harpo vorgeschlagene. Mit diesem Ansatz können Sie komplexeren Code entwickeln:
quelle
Anzeige zum Übertragen des Prozessauslösers SameNameASTrasferedFile.trg, die nach Abschluss der Dateiübertragung erstellt wird.
Richten Sie dann FileSystemWatcher ein, das ein Ereignis nur für die * .trg-Datei auslöst.
quelle
Ich weiß nicht, was Sie verwenden, um den Sperrstatus der Datei zu bestimmen, aber so etwas sollte es tun.
quelle
Eine mögliche Lösung wäre, einen Dateisystemwatcher mit einigen Abfragen zu kombinieren.
Bei jeder Änderung an einer Datei benachrichtigt werden. Wenn Sie benachrichtigt werden, überprüfen Sie, ob diese gemäß der aktuell akzeptierten Antwort gesperrt ist: https://stackoverflow.com/a/50800/6754146 Der Code zum Öffnen des Dateistreams wird aus der Antwort kopiert und leicht modifiziert:
Auf diese Weise können Sie nach einer gesperrten Datei suchen und benachrichtigt werden, wenn sie über den angegebenen Rückruf geschlossen wird. Auf diese Weise vermeiden Sie übermäßig aggressive Abfragen und erledigen die Arbeit nur, wenn sie möglicherweise tatsächlich geschlossen wird
quelle
Ich mache es genauso wie Gulzar, versuche es einfach weiter mit einer Schleife.
Tatsächlich kümmere ich mich nicht einmal um den Dateisystem-Watcher. Das Abfragen eines Netzwerklaufwerks nach neuen Dateien einmal pro Minute ist günstig.
quelle
Verwenden Sie einfach das geänderte Ereignis mit dem NotifyFilter NotifyFilters.LastWrite :
quelle
Beim Hinzufügen eines Outlook-Anhangs ist ein ähnliches Problem aufgetreten. "Using" hat den Tag gerettet.
quelle
Wie wäre es damit als Option:
Wenn die Dateigröße beim Erstellen vorab zugewiesen wird, erhalten Sie natürlich ein falsches Positiv.
quelle