Problem beim Öffnen/ Lesen von Textdateien mit CGI-Script

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
mintpc
User
Beiträge: 50
Registriert: Montag 23. Januar 2012, 12:44

Hallo zusammen,
ich hoffe, die Frage ist an dieser Stelle richtig platziert.

Ich habe ein CGI-Script geschrieben, das beim Ausführen eine Textdatei liest und dann evtuell etwas reinschreibt. Etwa so:

Code: Alles auswählen

 dat = open("Dateiname", "r")
 a = dat.readline()
 dat.close 
 ... 
 dat = open("Dateiname","w")
 dat.write("hallo")
 dat.close
Das Problem ist nun, dass die Datei zuerst gelesen wird, aber der zweite Zugriff
funktioniert nicht mehr. Scheinbar dauert der Zugriff (Öffnen und Schließen) der
Datei zu lange, so dass der folgende Schreibbefehl nicht mehr ausgeführt wird (oder
werden kann)

Das Problem wird auch nicht durch zwei Anweisungen wie:

Code: Alles auswählen

dat = open ("dateiname", "r+")
 a = dat.read()
 dat.write("hallo")
 dat.close
gelöst. Auch hier wird nur die erste Anweisung ausgeführt.

Manchmal wird die Datei sogar (scheinbar) gar nicht richtig mehr geschlossen.

Nun also die Frage:
Gibt es die Möglichkeit bei dem CGI-Script, irgendwie zu warten, bis der erste Dateizugriff
erfolgt ist? (Eine Lösung über eine Timer "timer.timer()" ging auch nicht, da der Timer alles
komplett bis zur Ausführung blockiert).

Vielen Dank schonmal, falls mit jemand einen Hinweis geben kann!
mintpc
deets

Du rufst nicht wirklich close auf.
Da fehlen die Klammern. Am besten verwendest du das with-Statement. Dann kann sowas nicht passieren.

Und was passiert wenn requests gleichzeitig komme
? Dann fliegt dir das alles um die Ohren. Du brauchst noch ein Prozess-übergreifendes Lock. Oder gleich ne DB benutzen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Zudem sei vielleicht doch noch der Hinweis erlaubt, auf ein WSGI basiertes Framework zurückzugreifen. Flask z.B. hat einen eingebauten Support für Cookies - evtl. reicht das schon aus?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mintpc
User
Beiträge: 50
Registriert: Montag 23. Januar 2012, 12:44

Die Klammern bei close() hatte ich schon, sonst hätte es ja nicht funktioniert. Das ist ja nicht das Problem.
Sondern das Problem ist, dass die beiden Lese- / Schreib-Zeilen nicht beide(!) ausgeführt werden.
Dieses Problem hat ja auch nichts mit ner Datenbank oder Cookies zu tun.

Auf meinem Rechner ausgeführt wartet der zweite Zugriffsbefehl ja, bis der erste abgearbeitet ist.
Greift dieses Prinzip beim serverseitig ausgeführten CGI-Script nicht mehr?
deets hat geschrieben:Du brauchst noch ein Prozess-übergreifendes Lock.
Genau um dieses "Lock" geht es mir. Wie mache ich das? Oder kann das ein Python-CGI-Script gar nicht?

mintpc
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Ich habe mich mit sowas noch nicht beschäftigt, aber wäre fcntl.lockf nicht eine Option?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mintpc hat geschrieben:Die Klammern bei close() hatte ich schon, sonst hätte es ja nicht funktioniert. Das ist ja nicht das Problem.
Dann poste doch auch bitte korrekten Quellcode... woher sollen wir denn so etwas ahnen?
mintpc hat geschrieben: Dieses Problem hat ja auch nichts mit ner Datenbank oder Cookies zu tun.
Nö - aber evtl. ließe es sich damit lösen. Ich weiß ja nicht, wozu diese Datei dient, aber evtl. reicht Dir ja auch ein Cookie. Damit würdest Du das Problem umgehen - zumindest, wenn Du auf eine Lösung zurückgreifst, die so etwas anbietet.
mintpc hat geschrieben: Genau um dieses "Lock" geht es mir. Wie mache ich das? Oder kann das ein Python-CGI-Script gar nicht?
Schau Dir doch mal an, wie Werkzeug das löst. Flask basiert darauf und nutzt das Modul entsprechend selber für seine Cookies.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mintpc
User
Beiträge: 50
Registriert: Montag 23. Januar 2012, 12:44

Hyperion hat geschrieben:Dann poste doch auch bitte korrekten Quellcode... woher sollen wir denn so etwas ahnen?
Ja, mein Fehler.

Also, prinzipiell will ich Python lernen und mir ist diese Sache mit den Textdateien aufgefallen.
Und für jemanden der Python lernt ist es ja schon interessant zu wissen, ob Python bei der Arbeit
und dem Zugriff einer Textdatei, die irgendwo auf einem Server liegt und auf die ein CGI-Script zugreift
und "sicher" ist, d.h. sequentiell auf diese Datei zugreift und mit seinen Befehlen wartet, bis der erste abgearbeitet
ist oder halt "nicht sicher" ist. D.h. es ist interessant zu wissen (finde ich), ob da Befehlszeilen "verloren" gehen
können.
Wenn ich auf meinem Rechner auf eine Textdatei zugreife ist das ja nicht der Fall, dass eine Anweisung übersprungen wird.
Hier arbeitet Python ja schön zeilenweise und wartet, bis die Datei gelesen oder geschrieben ist. Erst dann gehts weiter.

Wie ist es aber nun bei einem Provider, der Python anbietet?

Ich hoffe, meine Frage ist damit genau genug formuliert.

mintpc
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nein, der Ablauf eines Scriptes ändert sich nicht - das wäre ja der semantische Horror schlecht hin. Ich vermute bei Dir schlicht ein Rechteproblem - vermutlich hast Du Lese- aber keinen Schreibzugriff ;-)

Ich hatte da zu kompliziert gedacht und bin von mehreren parallelen Zugriffen ausgegangen - das Problem würde übrigens so bestehen bleiben, wenn Du Deinen Code so lässt. Mein Link zeigt aber dafür eine Lösung. Im Web kann so etwas natürlich leicht passieren, was lokal eher keine Rolle spielt.

Generell würde ich Dir doch empfehlen von CGI die Finger zu lassen; es gibt hier auch Leute, die das zum Lernen empfehlen, aber ich würde doch zu einem Rahmenwerk raten. Insbesondere, da WSGI die Schnittstelle für Webapps in Python ist - und das will man nicht Low level programmieren :-D

Du solltest Dateien unabhängig von allem aber mit `with` öffnen, was deets schon ansprach:

Code: Alles auswählen

with open(...) as handler:
    # handler ist hier file object; ein explizites handler.close() braucht es nicht!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
deets

@Hyperion

Ich denke schon, dass der Ablauf des Skriptes sich aendern kann - wenn der OP zB CGIHTTPServer verwendet auf seinem lokalen Rechner, aber nicht auf dem Server.

@mintpc

Grundsaetzlich garantiert Python natuerlich nicht, dass 2 Prozesse, die auf ein und dieselbe Datei zugreifen, dass diese Zugriffe sequentiell stattfinden. Du musst das wie ich schon sagte explizit sicherstellen, durch locking.

Und eine DB wuerde dabei sehr wohl helfen, weil sie eben genau solche konkurrierenden Zugriffe erlaubt & selbst serialisiert. Ob es wirklich die richtige Wahl ist, haengt natuerlich von den tatsaechlich geschriebenen Daten ab.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

deets hat geschrieben: Ich denke schon, dass der Ablauf des Skriptes sich aendern kann - wenn der OP zB CGIHTTPServer verwendet auf seinem lokalen Rechner, aber nicht auf dem Server.
Moment: Reden wir hier aneinander vorbei? Du willst doch nicht behaupten, dass Python sich bei diesem Code

Code: Alles auswählen

print "foo"
print "bar"
auch so verhalten kann, als hätte man

Code: Alles auswählen

print "bar"
print "foo"
geschrieben?

Es mag ja sein, dass Python von außen abgebrochen wird, bevor es `print "bar"` abarbeiten konnte, aber die Reihenfolge kann doch nicht geändert werden...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
deets

Nein, davon reden wir natuerlich nicht. Oder ich zumindest... ;)

Sondern davon, dass der OP angeblich unterschiede im Laufzeitverhalten zwischen lokal & auf dem Server beobachtet hat. Wofuer konkurrierende Zugriffe eine *moegliche* Erklaerung waeren. So habe ich ihn verstanden, und darauf bezog ich mich.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Na da bin ich ja beruhigt :-D Ich habe den Bezug zu mir nicht richtig gedeutet, bzw. Du mich nicht richtig verstanden, da ich vom Ablauf eines Scriptes sprach - das hat mit paralleler Ausführung ja nichts zu tun.
deets hat geschrieben: Sondern davon, dass der OP angeblich unterschiede im Laufzeitverhalten zwischen lokal & auf dem Server beobachtet hat. Wofuer konkurrierende Zugriffe eine *moegliche* Erklaerung waeren. So habe ich ihn verstanden, und darauf bezog ich mich.
Ja, so hatte ich es auch erst aufgefasst - aber ich habe da doch den starken Verdacht, dass es einfach an den Rechten liegt. Bei so simplen Code und der Spekulation, dass das Einlesen beendet wird, bevor der Server den Prozess killt, sollte das die einfachste Erklärung sein ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mintpc
User
Beiträge: 50
Registriert: Montag 23. Januar 2012, 12:44

Die Rechte hatte ich schon richtig gesetzt. Darauf kam ich schon.

Es sind hier wohl tatsächlich zwei konkurrierende Prozesse, und der letztere der beiden
Prozesse wird gestoppt. Anders kann ich mir das halt auch nicht erklären.
Aber, es wunderte mich!! Sollte ja eigentlich nicht sein.


mintpc
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Das musst Du jetzt mal bitte präzisieren: Du hast also ein Script, welches Du per CGI aufrufst. Sobald Du dieses zwei mal parallel aufrufst, kommt es zu den geschilderten Problemen? Oder verhält es sich noch anders?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mintpc
User
Beiträge: 50
Registriert: Montag 23. Januar 2012, 12:44

Nein, ich rufe das Script genau einmal auf.
Das Script öffnet eine Datei, liest, schreibt und schließt.

Nur wird Schreibbefehl nicht ausgeführt. Kommentiere ich den Lesebefehl aus,
wird der Schreibbefehl ausgeführt.

Wenn gelesen wird wird der sich anschließende Schreibbefehl also nicht ausgeführt.

Ich vermute nun, dass die Datei vom Lesebefehl noch zugriffsgesperrt ist und der Schreibbefehl
abgebrochen wird.

Setzte ich die ganze Anweisungskette nämlich in einen try-except-Block, wird stets except
aufgerufen. Beim Auskommentieren des Lese (bzw. des Schreibbefehls) geht alles.

Wahrscheinlich sind die Operationen auf ner Textdatei einfach zu langsam?!?

mintpc
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mintpc hat geschrieben: Setzte ich die ganze Anweisungskette nämlich in einen try-except-Block, wird stets except
aufgerufen.
Du Schlumpf! Wenn eine Exception geworfen wird, dann sage uns das doch und poste diese hier :roll:

Wie sollen wir das denn raten? ;-)

Vermutlich gibt Dir die Exception einen Aufschluss darüber, was schief läuft. Also poste die exakte Meldung doch mal hier - am besten in Kombi mit dem exakten Quellcode, der diese auslöst. (Das muss nicht das gesamte Script sein!)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mintpc
User
Beiträge: 50
Registriert: Montag 23. Januar 2012, 12:44

Also, ich hab gerade mal ne Datenbank probiert.
Da klappt alles, 100 Schreib- und Lesebefehle in einer Schleife ohne Fehler. Ich glaube zwar mittlerweile,
dass ne Datenbank im Internet doch besser ist, aber nun bin ich doch allzusehr an dem
Fehler bei der Dateiverarbeitung interessiert!! Ist ja spannend! :-)
Hyperion hat geschrieben:Vermutlich gibt Dir die Exception einen Aufschluss darüber, was schief läuft. Also poste die exakte Meldung doch mal hier - am besten in Kombi mit dem exakten Quellcode, der diese auslöst.
Jaaaa ..... mit Exception meinte ich den "except-Block", wo ich nur print("Fehler") reingeschrieben hatte. Also, der Quelltext sah so aus:

Code: Alles auswählen

try:
      dat1 = open(Dateiname,"r+")                        <---- hier hatte ich auch "a, w, r" etc. probiert
      Liste =[Nachricht+"\n",str(Zeit)+"\n"]
      dat1.writelines(Liste)
      LeseListe = dat1.readlines()                         <------ hier muss der Fehler liegen
      print(LeseListe[0])
      print(LeseListe[1])  
      dat1.close()
except:
      print("Fehler")
(Ich bin ja noch Anfänger.) Wie lasse ich mir denn die Fehlermeldung bei ner Exception anzeigen?? In meinem
Python-Buch finde ich nur die von mir aufgeschriebene Lösung.

mintpc
Zuletzt geändert von mintpc am Montag 23. Januar 2012, 21:26, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mintpc hat geschrieben: Jaaaa ..... mit Exception meinte ich den "except-Block", wo ich nur print("Fehler") reingeschrieben hatte. Also
try:
.....
except:
print("Fehler")


(Ich bin ja noch Anfänger.) Wie lasse ich mir denn die Fehlermeldung bei ner Exception anzeigen??
Indem Du das ganze try...except weglässt! Dann wird die Exception ausgelöst und das Programm bricht ab. Danach kannst Du im Log nachlesen, was der Interpreter ausgibt. Alternativ gibt es iirc ein "Debugging"-Modul für CGI, welches einem die Ausgaben auch als HTML-Seite rendert.
mintpc hat geschrieben: In meinem
Python-Buch finde ich nur die von mir aufgeschriebene Lösung.
Wie heißt denn Dein Buch? Irgend wie erahne ich mal, dass es sich irgend wie um eines der Herren Ernesti / Kaiser handelt aus dem Galileo-verlag... :-D

Ohne lange Erklärung: Du darfst niemals alle Excpetions abfangen! Im Moment "verschluckst" Du die Meldung einfach - Du hast gerade gelernt, wieso das schlecht ist: Wenn man keine Ahnung hat, was alles schief laufen kann, dann wird das Debuggen erschwert bzw. unmöglich gemacht.

Erst wenn Du weißt, welche Exception Du abfangen und sinnvoll behandeln willst, solltest Du diese auch per `try:...except: ExceptionType` gezielt abfangen und entsprechend behandeln.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mintpc
User
Beiträge: 50
Registriert: Montag 23. Januar 2012, 12:44

Sorry, hatte grad nochmal die Mitteilung geändert.

Versuche das mit dem except mal....


Das Buch ist von Thomas Theis, finde ich gar nicht so schlecht.

mintpc
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mintpc hat geschrieben:Sorry, hatte grad nochmal die Mitteilung geändert.
Naja, das hat ja nichts am Problem geändert ;-)
mintpc hat geschrieben: Das Buch ist von Thomas Theis, finde ich gar nicht so schlecht.
Hm... also wenn das da tatsächlich so drin steht und tatsächlich für den praktischen Einsatz so empfohlen wird, so ist das ein grober Fehler im Buch! Niemals einfach so alle Exceptions abfangen. Punkt.

Bist Du sicher, dass er das nicht als Negativbeispiel aufführt oder gar davor warnen will?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten