Problem beim einlesen langer textdateien

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
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

Hallo ihr lieben,

ich habe da ein kleines programm das messdaten aus einem textfile einliest und diese dann etwas anders darstellt, um sie später dann mit ANSYS als array einbinden zu können. für eine kleine testdatei funktioniert alles ohne probleme, nur bei einer tatsächlichen messdatei (so 13000+ lines) hängt sich die python shell dann auf, und zwar schon etwa ab der 120 zeile die das programm aus d messdatei einliest.

hier mal der quellcode:

Code: Alles auswählen

delimiters=[chr(9), chr(13)]
input_file=open("test.txt","r")
#output_file=open("xxx.txt","w")


#a=[]
line=input_file.readline()
while line:
 i=j=0
 linelenght=len(line)
 for i in range(linelenght):
  if line[i] in delimiters:
      #a.append(line[j:i]+" ")
      print Convert2Ansys(line[j:i],10,4)
      #output_file.write(Convert2Ansys(line[j:i],10,4)+" ")
      j=i+1
 #output_file.write(Convert2Ansys(line[j:i],10,4)+"\n")
 #a.append(line[j:i]+chr(13))
 print Convert2Ansys(line[j:i],10,4)
 line=input_file.readline()
 
input_file.close()
#print a
#output_file.close()
das Convert2Ansys ist auch recht kurz:

Code: Alles auswählen

def Convert2Ansys(string,w,d):
 """ converts string to a fortran floatnumber Fw.d
     actually only converts string to a total lenght of w characters
 string: has to be alphanumeric
 """
 #if string.isalnum()==False: return False 
 if string.find('.')!=-1: # komma-zahl ?
   while len(string)!=w:    # ja, einfach mit 0 auffüllen bis länge erreicht ist
     string+="0"
 else:
   while len(string)!=w:  # 0 vor der zahl einfügen
    string="0"+string

 return string
und macht eigentlich nichts anderers als ein paar 0 vor/nach der zahl einfügen damit die zahlen schön im Fortran format dastehen.

wo ist jetzt das problem im code ? für kurze messdateien funktionert das ohne probleme, bei langen crashd eben d. shell. und ich hab absolut keine idee warum... :(

ich hab schon probiert das ganze mal in ner liste anzulegen, oder eben das outputfile gleich zeilenweise zu schreiben. und selbst wenn beides nicht ausgeführt wird (die # zeilen) hängt sich die shell schon nur beim einlesen der zeilen auf. hier noch kurz ein ausschnitt einer typischen meßdatei:

130.7859 -5.503439 0.05145264
130.8374 -5.882718 0.05145264
130.8888 6.109447 0.05145264
130.9403 6.336176 0.05145264
130.9917 -6.341985 0.05145264
131.0432 6.347794 0.05143738
131.0946 6.172206 0.05145264

an der stelle an ders normalerweise abstürtzt ist auch kein besonderer zahlenwert der einen crash verursachen würde - hab den schon mal rauskopiert und separat getestet, ging auch alles fehlerfrei,

wo ist d wurm versteckt ? ich find einfach nix :(

danke für jede hilfreiche antwort,
holzdolph
BlackJack

Überleg Dir mal was bei `Convert2Ansys()` passiert, wenn ``len(string)`` grösser als `w` ist…

Dann wäre es nett wenn Du ordentlich 4 Leerzeichen pro Ebene und vor allem *konsistent* einrücken würdest.

Für eine Schleife über die Zeilen einer Datei kann man *direkt* über das Dateiobjekt iterieren und mir scheint Du hast da recht umständlich die `split()`-Methode auf Zeichenketten nachgebaut.
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

argh dieses "sch...öne" einrücken, bin gewohnt meine klammern da zu machen wo ich will :)

aber es liegt net am convert2ansys, auch wenn man das mal rausnimmt hängt sich die shell auf bei der langen datei
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Um eine Ganzzahl auf eine bestimmte Länge zu expandieren, kannst du %-Formatierung (siehe Doku) verwenden:

Code: Alles auswählen

>>> '%016d' % 123456789
'0000000123456789'
Das berücksichtigt auch negative Zahlen:

Code: Alles auswählen

>>> '%010d' % -123456789
'-123456789'
Dein Weg auch? :)

Möglicherweise noch einfacher ist die Verwendung von `str.zfill(width)`, das allerdings von einem String ausgeht (was aber kein wirkliches Problem ist).
Zum Auffüllen mit anderen Zeichen als einer Null eignen sich `str.ljust(width[, fillchar])` respektive `str.rjust(width[, fillchar])`.

Ob sich das für die Float-Formatierung ebenfalls gebrauchen lässt, musst du mal selbst herausfinden.


Hier noch ein Beispiel mit Python 2.5, um elegant und speicherfreundlich eine Datei zeilenweise einzulesen:

Code: Alles auswählen

from __future__ import with_statement

with open('somefile.txt', 'rb') as f:
    for line in f:
        do_stuff(line)
Dabei wird die Datei am Ende des Blocks automatisch wieder geschlossen.
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

BlackJack hat geschrieben:Überleg Dir mal was bei `Convert2Ansys()` passiert, wenn ``len(string)`` grösser als `w` ist…
das ist im moment egal da im moment natürlich keine datensätze auftreten bei denen das d fall wäre, also daran liegts net.
man kann alles rausnehmen ausser dem zeilenweisen einlesen d datei und d shell stürzt ab, wenns ne bessere methode gibt das einzulesen als mit dieser whileschleife bitte wo find das :)
BlackJack hat geschrieben:mir scheint Du hast da recht umständlich die `split()`-Methode auf Zeichenketten nachgebaut.
mit split wird das auch net kürzer....
BlackJack

Selbst wenn es mit `split()` nicht kürzer würde, wäre es wenigstens nicht so umständlich und leichter zu lesen.

Code: Alles auswählen

import sys
from itertools import imap


def convert2ansys(string, width=10):
    if '.' in string:
        return string.rjust(width, '0')
    else:
        return string.ljust(width, '0')

def convert_line(line):
    return ' '.join(imap(convert2ansys, line.split())) + '\n'

in_file = open('test.txt', 'r')
out_file = sys.stdout
out_file.writelines(imap(convert_line, in_file))
in_file.close()
out_file.close()
Sieht nicht so aus, als wenn Dein Code mit negativen Zahlen zurecht käme.

Ansonsten kann ich da nichts erkennen was zu einem Hänger führen würde. Entweder Du hast doch "Zahlen" die zu lang sind oder das Problem liegt woanders.

Stell mal ein minimales lauffähiges Programm, dass das Problem aufweist zusammen.
The Spirit
User
Beiträge: 276
Registriert: Freitag 8. Juni 2007, 08:50
Wohnort: 84xxx Bereich
Kontaktdaten:

wie groß ist denn das file etwa in mb?
ich mache hier "fast" das gleiche und meine logfiles haben teilweise 10 mb und mehr bei etwa 500.000 zeilen.
und bei mir läuft das alles ohne probleme und sehr schnell
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

Y0Gi hat geschrieben: Dein Weg auch? :)
ja, weil keine ganzen zahlen im datensatz auftauchen. und bei dezimalzahlen füllts die nullen ja auch hinten an. dh. es hätte schon

Code: Alles auswählen

while len(string)!=w:    # ja, einfach mit 0 auffüllen bis länge erreicht ist
     string+="0"
gereicht, werds aber wohl doch für alle fälle mit d. string-konvertierung machen.

habe das problem übrigens gefunden. ursprünglich wollte ich die zeilen in eine liste einlesen (die # zeilen) anstatt das gleich zeilenweise wieder in die neue datei zu schreiben. dabei hängt sich die shell dann auf. warums auch zu nem crash kam wenn man die zeilen rausnimmt und dann nurmehr direkt zeilenweise lest/schreibt versteh ich nicht wirklich - heute gehts - hab nix geändert am code :) da wurde wohl beim ersten crash eventuell d speicher nicht mehr richtig freigegeben und darum gabs lauter folgecrash´s oder ka eigentlich^^

danke für die ganzen hilfreichen beiträge,
lg holzdolph
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

BlackJack hat geschrieben:

Code: Alles auswählen

import sys
from itertools import imap


def convert2ansys(string, width=10):
    if '.' in string:
        return string.rjust(width, '0')
    else:
        return string.ljust(width, '0')

def convert_line(line):
    return ' '.join(imap(convert2ansys, line.split())) + '\n'

in_file = open('test.txt', 'r')
out_file = sys.stdout
out_file.writelines(imap(convert_line, in_file))
in_file.close()
out_file.close()
Sieht nicht so aus, als wenn Dein Code mit negativen Zahlen zurecht käme.
sieht zwar gleich besser aus als mit d while - nur kenn ich halt die ganzen schönen packages net - und nen while kommand gibts in (fast) jeder programmiersprache :)
nur bei neg. ganzen zahlen baut das prog hier genauso mist wie meins :)
(aus -3 wird zb 000000-3) und rjust/ljust muss man noch vertauschen damit zumindest d rest richtig aussieht.

mit dem tipp für die richtige konvertierung vom yogi wirds aber wohl noch alles richtig umwandeln.

thx nochmal @alle für die flotten und brauchbaren antworten
lg,
holzdolph
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

Y0Gi hat geschrieben:Um eine Ganzzahl auf eine bestimmte Länge zu expandieren, kannst du %-Formatierung (siehe Doku) verwenden:

Code: Alles auswählen

>>> '%016d' % 123456789
'0000000123456789'
Das berücksichtigt auch negative Zahlen:

Code: Alles auswählen

>>> '%010d' % -123456789
'-123456789'
das wär zwar die "schönste" methode, auf die schnelle hab ich aber keinen weg gefunden die formatierung variabel zu machen, da man ja unter den '' keine variable länge angeben kann
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Eine variable Formatierung ist nun wirklich nicht die Schwierigkeit:

Code: Alles auswählen

"%0" + str(length) + "d"

"%%0%dd" % length
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

:-)

Code: Alles auswählen

>>> "%0*i" % (15, 12345)
'000000000012345'
>>> "%0*i" % (15, -12345)
'-00000000012345'
>>> 
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@Gerold
Das sieht ja mal hübsch aus, kannte ich noch gar nicht. Mal wieder was dazu gelernt :)
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

coole sache :) mein 5ter tag mit python und das sieht ja schon vieeel hübscher aus^^

eine frage noch zu dem sehr tollen iterativen funktionsaufruf mit dem imap, wie übergeb ich da jetzt eine width ? egal wo ich das hinschreib das passt ihm net^^

Code: Alles auswählen

import sys
from itertools import imap


def convert2ansys(string, width=10):
     x = float(string)
     s = "%0*f" % (width, x)
     return s

def convert_line(line):
    return ' '.join(imap(convert2ansys, line.split())) + '\n'

in_file = open('test.txt', 'r')
out_file = sys.stdout
out_file.writelines(imap(convert_line, in_file))
in_file.close()
out_file.close()
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Indem du statt die Funktion in `imap` eine anonyme Funktion verwendest. Also wird aus

Code: Alles auswählen

return ' '.join(imap(convert2ansys, line.split())) + '\n'

Code: Alles auswählen

return ' '.join(imap(lambda string: convert2ansys(string, 5), line.split())) + '\n'
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Und spätestens jetzt sollte man auf eine (ebenfalls iterative) Generator Expression umsteigen:

Code: Alles auswählen

return ' '.join(imap(lambda string: convert2ansys(string, 5), line.split())) + '\n'
wird zu:

Code: Alles auswählen

return ' '.join(convert2ansys(string, 5) for string in line.split()) + '\n'
Holzdolph
User
Beiträge: 23
Registriert: Donnerstag 22. November 2007, 17:43

verstehn muss ich es ja nicht - hauptsache es funktioniert :)

schönen dank nochmal an alle für die hilfe, bin inzwischen wieder mit der eigentlichen simulation beschäftigt

lg
holzdolph
Antworten