Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   C++ Warten bis Datei geschlossen ist (https://www.delphipraxis.net/149530-warten-bis-datei-geschlossen-ist.html)

TheReaper 23. Mär 2010 16:40


Warten bis Datei geschlossen ist
 
Hallo, :hi:

Ich nutze die Funktion ReadDirectoryChangesW um einen Ordner zu überwachen, ob neue Dateien geschrieben, oder verändert wurden. Sobald ich die Info kriege, wird die in meinem Programm readonly geöffnet. Leider kann die nicht immer geöffnet werden, weil die Datei von außerhalb noch nicht fertig geschrieben bzw. geschlossen wurde. Also einfach warten bis sie zu ist, dachte ich mir. Aber wie kann ich das ohne polling und sleeps prüfen? Ich hatte die Idee das mit einem event zu synchronisieren, aber process übergreifend wird das wohl nix, oder?
Achso, das "schreiber programm" ist auch von mir. Da gibts also keine Probleme etwas am Code zu ändern.

himitsu 23. Mär 2010 17:04

Re: Warten bis Datei geschlossen ist
 
Schick doch dem lesenden Programm eine Message, wenn fertig.
Oder (müssen die Daten unbedingt erst als Datei abgespeichert werden?) schick die Daten direkt an das andere Programm.

Hier im Forum suchenIsFileInUse, aber ohne Polling geht auch das nicht.

Und CloseHandle der schreibenden Anwendung zu hooken wäre etwas übertrieben.

TheReaper 23. Mär 2010 17:47

Re: Warten bis Datei geschlossen ist
 
Polling ist nur der allerletzte ausweg, da es nur Ressourcen verbraucht und unsauber Programmiert ist. Nachrichten, Events oder sonstwas kann ich auch nicht schicken, weil mir gerade eingefallen ist, dass ich doch nichts an dem Schreiber ändern kann. Der Schreiber ist nur ein Emulator, damit ich besser testen kann. Ich muss also damit auskommen, was Windows an Nachrichten schickt.

ele 23. Mär 2010 18:19

Re: Warten bis Datei geschlossen ist
 
Da kann FindFirstChangeNotification wahrscheinlich weiterhelfen.

Tryer 23. Mär 2010 18:21

Re: Warten bis Datei geschlossen ist
 
Ein ausgelagerter Thread der den Rest der Anwendung nicht ausbremst und solange versucht die Datei zu öffnen bis GetLastError <> ERROR_SHARING_VIOLATION, sonst Sleep(10?). Da der Thread die meiste Zeit schläft braucht er kaum Zeit.
Was wird dadurch also großartig an Resourcen "verbraucht"? Auf jeden Fall deutlich weniger als durch ReadDirectoryChanges - das bremst bei falscher Implementierung "richtig".

"Unsauber programmiert" ist das ReadDirectoryChanges von Microsoft, da es die Events zu Zeiten feuert wo noch niemand etwas mit anfangen kann.
Eine Nachricht ala "jetzt darfst Du" gibt es nicht.
Das Polling ist in meinen Augen die einzig sinnvolle Lösung.


MfG,
Dirk

EDIT: FindFirstChangeNotification feuert auch zu früh, es kann also auch damit vorkommen das die Datei noch nicht zugriffsbereit ist.

TheReaper 23. Mär 2010 19:20

Re: Warten bis Datei geschlossen ist
 
Bis jetzt läuft das Programm mit der Polling methode. Das ReadDirectoryChanges ist richtig implementiert. Es geht nur noch darum das ganze zu optimieren und sauber zu schreiben. Und da ist das Polling nicht gerade schön. Außerdem ständig createfile aufrufen kann auch schief gehen. Wenn beim schreiben irgendwas schief läuft und die Datei nicht geschlossen werden kann, wird immer ein Fehler zurück gegeben und bin in einer Endlosschleife.

FindXXXChangesNotification ist das selbe in grün mit dem Nachteil, dass man nicht den Dateinamen kriegt. Das hab ich auch schon hinter mir. :)
Naja, anscheinend gibts unter XP keine gute Möglichkeit. Trotzdem Danke für die Antworten. :dp:

DelphiBandit 24. Mär 2010 07:38

Re: Warten bis Datei geschlossen ist
 
Hast Du denn Einfluss auf den Emulator, soll heissen kommst Du an dessen Quelltexte dran und kannst ihn modifizieren? Wenn nein, vergiss die Beschreibung unten ;) OK, beim zweiten Lesen der Ursprungsnachricht - ja, hast Du :D

Ohne das Betriebssystem zu arg zu stressen lösen wir das mit dem Schreiben einer Semaphorendatei, welche vor dem Erstellen der Inhaltsdatei erstellt wird und eine andere Dateiendung, aber den gleichen Namen hat. Diese Dateiendung wird vom Einleser nicht verarbeitet.

Dann lädt der Schreiber seine Daten in der eigentlichen Datendatei ab. Solange parallel noch die Semaphorendatei existiert, wird noch nicht ausgelesen. Ist der Schreiber fertig, löscht er diese Datei - es wird wieder ein DirectoryChange ausgelöst - und der Inhalt wird anschliessend vom auslesenden Programm verarbeitet, weil die Semaphorendatei nicht mehr existiert.

Insgesamt werden dabei 3-4 DirectoryChanges ausgelöst

1.) Semphorendatei wird erstellt - die wird sowieso nicht verarbeitet
2.) Datendatei wird erstellt und mit Daten befüllt - wird nicht verarbeitet, weil parallel noch die 1.) Datei existiert
3.) Semphorendatei wird gelöscht -> ok, dann ist der Schreiber fertig und die Daten können ausgelesen werden
4.) ggf. Löschen der Datendatei

Nur nicht unbedingt multithreadingfähig, es sei denn die Threads tauschen sich aus, was sie gerade am verarbeiten sind.

TheReaper 24. Mär 2010 08:02

Re: Warten bis Datei geschlossen ist
 
Ja, ich hab Zugriff auf den Emulator code. Aber Emulatoren haben es so ansich, dass Sie reagieren müssen, wie ihr "echtes" Produkt. Und das kann ich nicht ändern. Also kann ich nich nach belieben irgendwas einbauen. Genau das ist das Problem. Wie gesagt, ich muss damit zurecht kommen, was Windows mir liefert.

DelphiBandit 24. Mär 2010 08:09

Re: Warten bis Datei geschlossen ist
 
Zitat:

Zitat von TheReaper
Ja, ich hab Zugriff auf den Emulator code. Aber Emulatoren haben es so ansich, dass Sie reagieren müssen, wie ihr "echtes" Produkt. Und das kann ich nicht ändern. Also kann ich nich nach belieben irgendwas einbauen. Genau das ist das Problem. Wie gesagt, ich muss damit zurecht kommen, was Windows mir liefert.

OK, schade :?

Anderer Ansatz, welcher mir gerade so in den Sinn kommt:
Die eingehenden Dateien mittels FileMove verschieben in ein anderes Verzeichnis. Die Dateien bei welchen das nicht klappt erstmal außen vor lassen. Und die in dem Zielverzeichnis verarbeiten. Aber das unterscheidet sich vom Aufwand her auch nicht wirklich vom Try&Error Versuch eine Datei zu öffnen.

TheReaper 24. Mär 2010 13:47

Re: Warten bis Datei geschlossen ist
 
Ich hab es jetzt hin bekommen. Und zwar krieg ich für jede Datei mehrere Messages die im FILE_NOTIFY_INFORMATION (fni) gespeichert werden. Ich versuche einfach nach jeder Message das File zu öffnen. Ungefähr so:
- Wenn Fehler bei Datei öffnen und GetLastError() == ERROR_SHARING_VIOLATION dann ignorieren und nächste Message aus fni nehmen
- Wenn Erfolg, Dateinamen merken, was damit machen und beim nächsten Durchlauf den Dateinamen ignorieren
- Bei anderen Fehlern einfach raus aus dem Thread und dem Nutzer ne Fehlermessage um die Ohren jagen. :)
Das wars im groben schon.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz