if Datei in Ordner mit Endlos -Schleife

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
bob1704
User
Beiträge: 27
Registriert: Dienstag 5. März 2013, 21:28

Hallo,
ich möchte mittels einer Endlos-Schleife überprüfen ob in einem Verzeichniss eine Datei mit einer gewissen Endung vorliegt.

Falls das der Fall ist soll in abhängikeit der Datei eiin bzw, mehrere Befehle ausgeführt werden.

Ist keine Datei mit der gewissen Endung vorhaden, soll die Schleife neu gestartet werden.

Hier meine Idee, welche allerdings noch nicht so ganz funktioniert:

Code: Alles auswählen

#!/bin/env python
##
##
#### -*- coding: utf-8 -*-
import os
import time
import sys
import commands
from twilio.rest import TwilioRestClient
###############################
account_sid = "xxx"
auth_token = "dgdfg"
client = TwilioRestClient(account_sid, auth_token)
###############################
### pwd vaiable zuweisen#######
mist, pfad = commands.getstatusoutput("pwd")
while True:
        for i in os.listdir(pfad) :
                if i[-4:] == ".f06":
                        cae_job = i[:-4]
                        print i
                        print cae_job
                        f06_file = open(i).read()
                        if "Fatal" not in f06_file:
                                sms_message = "Your CAE Job %s finished successfull" %cae_job
                                print "no fatal"
                                break
                        elif "Fatal" in f06_file:
                                print "Job not successfull"
                                sms_message = "Your CAE Job %s was NOT successfull" %cae_job
                                break
                  else: 
                                continue
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Da ich das Problem nicht kenne, weil du nichts näheres erzählst habe ich mir den Code nicht angeschaut.
Ich halte das Modul Pinotofy für eine bessere Idee als eine permanente überprüfung per while xxx: os.listdir()
BlackJack

@bob1704: *Das* Problem mit dem Quelltext ist, das er gar nicht erst kompiliert, weil das ``else`` in der ``for``-Schleife anders eingerückt ist als das ``if``. Einrückung ist per Konvention vier Leerzeichen pro Ebene. Das ``else`` könnte man sowieso komplett weglassen, weil der Zweig an der Stelle nichts bewirkt, was nicht sowieso passieren würde.

Dann werden einige Importe gar nicht verwendet. Der `TwilioRestClient` wird erstellt, aber dann auch nicht verwendet. Das hätte man aus dem Beispiel also heraus lassen können.

Ob der Kodierungskommentar so tief in der Datei noch greift weiss ich nicht. Der sollte üblicherweise in der ersten oder zweiten Zeile stehen. Der Compiler muss dass wissen bevor der Quelltext in dem Modul übersetzt werden kann.

Anstelle des `commands`-Moduls sollte man mittlerweile das `subprocess`-Modul verwenden. Wobei das zum Ermitteln des aktuellen Arbeitsverzeichnisses überhaupt gar nicht nötig ist. Zum einen gibt es die Funktion `os.getcwd()` die das ohne externe Programmaufrufe und plattformunabhängig macht. Zum anderen kann man `os.listdir()` aber auch einfach den Pfad relativ angeben.

Der Name `mist` ist irgendwie nicht wirklich toll. Wenn man irgendwo einen Namen hinschreiben und an einen Wert binden muss, den man dann aber gar nicht verwendet, hat sich der einfache Unterstrich als Konvention eingebürgert.

Den Namen `i` sollte man nicht, und insbesondere in einer Schleife nicht, an Werte binden die einen anderen Typ als ganze Zahlen haben. Damit rechnet fast jeder Programmierer der `i`, `k`, oder `j` in einer Schleife sieht. Zumal das für Dateinamen auch ein sehr schlechter Name ist. `filename` wäre ein viel besserer.

Statt mit der „magischen” Zahl -4 zu operieren, sollte man besser die `endswith()`-Methode auf Zeichenketten und/oder `os.path.splitext()` zum trennen von Dateiname und Erweiterung verwenden. Man kann sich das Filtern auch mit dem `glob`-Modul einfacher machen.

Dateien die man öffnet, sollte man auch wieder schliessen. Sonst kann es irgendwann passieren, dass das Betriebssystem für den Prozess keine neuen Dateien mehr öffnen kann. Man darf sich hier nicht auf eine zeitnahe Speicherbereinigung durch die Laufzeitumgebung von Python verlassen, weil das explizit nicht garantiert wird. Die ``with``-Anweisung bietet sich an der Stelle an.

Der Name für den Datei*inhalt* ist irreführend. Der Inhalt ist ja nicht das Dateiobjekt.

Wenn man in einem ``elif`` genau das Gegenteil von der Bedingung im ``if`` testet, dann will man eigentlich einfach nur ein ``else`` verwenden.

Dein Quelltext könnte dann letztendlich ungefähr so aussehen:

Code: Alles auswählen

#!/bin/env python
# -*- coding: utf-8 -*-
import os
from glob import glob


def main():
    while True:
        filenames = glob('*.f06')
        if filenames:
            filename = filenames[0]
            cae_job_name, _extension = os.path.splitext(filename)
            print filename
            print cae_job_name
            with open(filename) as f06_file:
                file_content = f06_file.read()
            if 'Fatal' not in file_content:
                print 'no fatal'
                sms_message = 'Your CAE Job {0} finished successfully'
            else:
                print 'Job not successful'
                sms_message = 'Your CAE Job {0} was NOT successful'
            sms_message = sms_message.format(cae_job_name)


if __name__ == '__main__':
    main()
Was soll eigentlich passieren wenn es mehrere Dateien mit der Endung gibt? Deine sowie die Lösung mit `glob()` verwenden dann *irgendeine* der Dateien. Es ist nicht garantiert welche das sein wird.

Und was passiert wenn das Programm eine Datei ausliest, die gerade von einem anderen Programm geschrieben und damit noch nicht vollständig ist. Dann wird vielleicht kein 'Fatal' gefunden, obwohl das noch in der Datei landen wird.
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

@BlackJack

Is anstatt

Code: Alles auswählen

_, pfad = commands.getstatusoutput("pwd")
das folgende auch pythonisch?

Code: Alles auswählen

pfad = commands.getstatusoutput("pwd")[1]
Mal davon abgesehen, dass das commands modul noch benutzt wird :P
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Hier eine Idee, wie man es auch machen könnte:

Code: Alles auswählen

import os
import glob
import time


def observe_directory(path, scan_interval=1):
    success_message = "Your Job %s finished successfull"
    error_message = "Your Job %s has failed"
    file_pattern = os.path.join(path, '*.f06')
    while True:
        for item in glob.glob(file_pattern):
            name, extension = os.path.splitext(os.path.basename(item))
            with open(os.path.join(path, item)) as f06_file:
                content = f06_file.read()
            if "Fatal" in content:
                print error_message % name
            else:
                print success_message % name
        break  # for testing
        time.sleep(scan_interval)


if __name__ == '__main__':
    path = os.getcwd()
    observe_directory(path)
Bei den print-statements liessen sich dann die jeweiligen Handler aufrufen. Jedoch weiß ich nicht, ob der Ansatz für den wirklich gedachten Zweck geeignet ist.
Die gelesenen Dateien müssten nach dem Lesen auch entfernt werden, damit sich die Meldungen nicht wiederholen.
bob1704
User
Beiträge: 27
Registriert: Dienstag 5. März 2013, 21:28

Hallo ,
erstmal vielen Dank für die Antworten.
BlackJack hat geschrieben:@bob1704Dann werden einige Importe gar nicht verwendet. Der `TwilioRestClient` wird erstellt, aber dann auch nicht verwendet. Das hätte man aus dem Beispiel also heraus lassen können.
Der Client wird schon verwendet, fehlt aber noch :)
BlackJack hat geschrieben:@bob1704:Ob der Kodierungskommentar so tief in der Datei noch greift weiss ich nicht. Der sollte üblicherweise in der ersten oder zweiten Zeile stehen. Der Compiler muss dass wissen bevor der Quelltext in dem Modul übersetzt werden kann.
Meinst du mit Kodierungskommentar %s ?
BlackJack hat geschrieben:@bob1704:Anstelle des `commands`-Moduls sollte man mittlerweile das `subprocess`-Modul verwenden. Wobei das zum Ermitteln des aktuellen Arbeitsverzeichnisses überhaupt gar nicht nötig ist. Zum einen gibt es die Funktion `os.getcwd()` die das ohne externe Programmaufrufe und plattformunabhängig macht. Zum anderen kann man `os.listdir()` aber auch einfach den Pfad relativ angeben.
Der Grund für das pwd Kommando ist, dass das Skript später in einem anderen Verzeichniss ausgeführt wird als es selber liegt.
Gibt es dafür eine Lösung mittels dem os. modul?

BlackJack hat geschrieben:Was soll eigentlich passieren wenn es mehrere Dateien mit der Endung gibt? Deine sowie die Lösung mit `glob()` verwenden dann *irgendeine* der Dateien. Es ist nicht garantiert welche das sein wird.
Für den Fall sollen vorher alle *.f06 im aktuellen Verzeichniss gelöscht werden.
BlackJack hat geschrieben:Und was passiert wenn das Programm eine Datei ausliest, die gerade von einem anderen Programm geschrieben und damit noch nicht vollständig ist. Dann wird vielleicht kein 'Fatal' gefunden, obwohl das noch in der Datei landen wird.
Das soll mittels einer Schleife welche die Dateigröße vergleicht abgesichert werden.
BlackJack

@bob1704: Mit Kodierungskommetar meine ich ``# coding: utf8`` oder etwas in der Richtung, was dem Compiler sagt in welcher Kodierung der Quelltext vorliegt.

Ich habe doch geschrieben das es `os.getcwd()` gibt. Wieso fragst Du dann noch nach einer Lösung mit dem `os`-Modul? Wobei immer noch gilt, dass man das nicht braucht, wenn man einfach den Pfad relativ zum aktuellen Arbeitsverzeichnis angibt.
bob1704
User
Beiträge: 27
Registriert: Dienstag 5. März 2013, 21:28

Hallo nochmal zusammen,
ich möchte meinen Code um einen Teil erweitern, welcher überprüft ob eine Datei gerade in das aktuelle Verzeichniss kopiert wird.

Dies hab ich über eine while Schleife realisiert, welche die Dateigröße überpüft.

Code: Alles auswählen

 
filesize1 = ""
filesize2 = "1"
while filesize1 != filesize2:
    filesize1 = os.path.getsize(filename)
    print filesize1
    time.sleep(5)
    filesize2 = os.path.getsize(filename)
    print filesize2

Allerdings bin ich damit irgrendwie noch nicht so ganz zufrieden...

Hat eventuell einer Verbesserungsvorschläge?

Danke u Gruß
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo bob1704,
man vermeidet normalerweise mehrfaches Aufrufen der gleichen Funktion:

Code: Alles auswählen

filesize = None
while True:
    previous_filesize = filesize
    filesize = os.path.getsize(filename)
    print filesize
    if filesize==previous_filesize:
        break
    time.sleep(5)
Nun zu den Problemen:
- egal wie klein die Datei ist, die Schleife braucht immer 5 Sekunden zum Durchlaufen
- wird über Netz kopiert und es kommt zu kleineren Aussetzern sind schnell mal ein paar Sekunden vorbei in denen nichts kopiert wird.
- nicht alle Dateisysteme, vor allem Netzwerklaufwerke aktualisieren die Dateigröße ständig
Antworten