LoadFromFile bei geöffneter Datei



  • Ich suche nach einer Datei in einem vorgegebenen Verzeichnis auf der Festplatte. Wenn die Datei gefunden wurde lade ich den Inhalt in eine Stringliste und lese ihn aus und lösche die Datei wieder. Parallel dazu schreibt eine andere Anwendung diese Datei. Wie kann ich absichern, dass die Datei von der anderen Anwendung nicht gerade geschrieben wird, also noch offen ist?

    Hier mein Code:

    auto_ptr<TStringList> stlMessages(new TStringList);
    TSearchRec sr;
    AnsiString path = myDirectory + "\\datei.txt";
    
    while(FindFirst(path, 0, sr) == 0) { //auf Datei warten
        stlMessages->LoadFromFile(path);
        if (stlMessages->Count > 1) {
            if (stlMessages->Strings[1] == "FILEEND") {
                if (stlMessages->Strings[0] == "Aktion A") {
    	        //hier wird Aktion A ausgeführt	
                }
    	        else if (stlMessages->Strings[0] == "Aktion B") {
    	        //hier wird Aktion B ausgeführt	
                }	
                //... weitere Aktionen ....		
    
                DeleteFile(path);
            }
        }			
        Application->ProcessMessages();
    }
    

    Ich erhalte ab und zu den Fehler:

    Datei C:\Users\User\Desktop\datei.txt kann nicht geöffnet werden. Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.
    


  • rudpower schrieb:

    while(FindFirst(path, 0, sr) == 0) { //auf Datei warten
        [...]
        Application->ProcessMessages();
    }
    

    Der Code erzeugt fast maximale CPU-Auslastung, bremst andere Anwendungen unnötig aus, verbraucht unnötig Strom etc. Hast du unter DOS programmieren gelernt? Unter Windows macht man das nicht so.

    Kannst du außerdem mal beschreiben, was du machen willst? Startest du die andere Anwendung, falls nein, wer startet die dann? Was für eine Anwendung ist das; eine von dir oder ein bestehendes Programm? Und gibt es vielleicht elegantere Wege, mit ihr zu kommunizieren, als so eine Textdatei?

    Edit: Format korrigiert



  • Bei der anderen Anwendung handelt es sich um ein bestehendes Programm. Die Kommunikation erfolgt über eine Textdatei. Darauf habe ich keinen Einfluss. Gestartet wird diese Anwendung von mir.

    Wie macht man den dies unter Windows richtig?

    Wäre die Nutzung des Timers besser?



  • rudpower schrieb:

    Gestartet wird diese Anwendung von mir.

    Wie macht man den dies unter Windows richtig?

    Sehr einfach. Wenn du die Anwendung mit CreateProcess() startest, bekommst du ein Prozeß- und ein Threadhandle. Auf solche Handles kann man mit WaitForSingleObject() warten. "Auf das Prozeß-Handle warten" ist dabei gleichbedeutend mit "auf die Beendigung des Prozesses warten". Danach schließt man beide Handles (!) mit CloseHandle() .

    Weil all diese Funktionen Fehlercodes zurückgeben und keine Exceptions werfen, muß man natürlich nach jedem Aufruf den Rückgabewert überprüfen und sich überlegen, was zu tun sinnvoll wäre, wenn die Funktion fehlschlägt.

    Wenn dein Programm auf das andere Programm wartet, ist natürlich das UI nicht mehr ansprechbar. Sollte dich das stören, dann kannst du einen Thread benutzen, in dem du auf den Prozeß wartest, so daß der UI-Thread weiterhin Messages verarbeiten kann.



  • Ganz so ist es nicht. Mein Programm lässt die CPU nicht unter Volllast laufen. Die Auslastung ist im Mittel unter 5%.

    Ich habe auch noch ein Delay von 2 Sekunden drin:

    while(FindFirst(path, 0, sr) == 0) { //auf Datei warten
        Delay(2);    
        stlMessages->LoadFromFile(path);
        if (stlMessages->Count > 1) {
            if (stlMessages->Strings[1] == "FILEEND") {
                if (stlMessages->Strings[0] == "Aktion A") {
                //hier wird Aktion A ausgeführt
                }
                else if (stlMessages->Strings[0] == "Aktion B") {
                //hier wird Aktion B ausgeführt
                }  
                //... weitere Aktionen ....    
    
                DeleteFile(path);
            }
        }          
        Application->ProcessMessages();
    }
    

    //Delay-Methode:

    void TfrmMain::Delay(int seconds) {
    	int startTime = GetTickCount();
    	while ((int(GetTickCount() - startTime) < (seconds * 1000)) && !frmSetHS5->hs5->stop) {
    		Application->ProcessMessages();
    		Sleep(1);
    	}
    }
    

    Wie kann man denn nun abfragen, ob die Datei gerade geöffnet ist?



  • Ich habe oben geschrieben wie man es richtig macht. Hast du das absichtlich übersehen?

    Faustregel: Wenn du TApplication::ProcessMessages() benutzt, machst du es falsch.



  • Ich soll also die andere Software über CreateProcess starten? Diese Software ist nicht von mir. Außerdem müssen dort noch einige Benutzereingaben gemacht werden bevor die Dateien erzeugt werden. Der Nachrichtenaustausch über Dateien ist so vorgegeben.



  • audacia schrieb:

    Ich habe oben geschrieben wie man es richtig macht. Hast du das absichtlich übersehen?

    Ich hätte da jetzt eher eine Lösung mittels ReadDirectoryChangesW in Betracht gezogen...



  • rudpower schrieb:

    Ich soll also die andere Software über CreateProcess starten? Diese Software ist nicht von mir.

    Das eine widerspricht doch dem anderen nicht. Du schreibst doch oben, daß du die andere Anwendung startest; habe ich das falsch verstanden?

    rudpower schrieb:

    Außerdem müssen dort noch einige Benutzereingaben gemacht werden bevor die Dateien erzeugt werden.

    Aha. Ich bin jetzt davon ausgegangen, daß das andere Programm halt seine Arbeit tut, die Ergebnisse in eine Datei schreibt und sich dann beendet. Falls dem nicht so ist, dann beschreibe doch mal das Interationsmuster etwas detaillierter.


Anmelden zum Antworten