Seite 1 von 1

Problem beim einlesen langer textdateien

Verfasst: Donnerstag 22. November 2007, 18:03
von Holzdolph
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

Verfasst: Donnerstag 22. November 2007, 18:19
von 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.

Verfasst: Donnerstag 22. November 2007, 18:35
von Holzdolph
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

Verfasst: Donnerstag 22. November 2007, 18:47
von Y0Gi
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.

Verfasst: Donnerstag 22. November 2007, 18:47
von Holzdolph
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....

Verfasst: Donnerstag 22. November 2007, 19:16
von 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.

Verfasst: Freitag 23. November 2007, 09:56
von The Spirit
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

Verfasst: Freitag 23. November 2007, 10:22
von Holzdolph
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

Verfasst: Freitag 23. November 2007, 10:42
von Holzdolph
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

Verfasst: Freitag 23. November 2007, 11:00
von Holzdolph
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

Verfasst: Freitag 23. November 2007, 12:09
von EyDu
Eine variable Formatierung ist nun wirklich nicht die Schwierigkeit:

Code: Alles auswählen

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

"%%0%dd" % length

Verfasst: Freitag 23. November 2007, 12:14
von gerold
:-)

Code: Alles auswählen

>>> "%0*i" % (15, 12345)
'000000000012345'
>>> "%0*i" % (15, -12345)
'-00000000012345'
>>> 
mfg
Gerold
:-)

Verfasst: Freitag 23. November 2007, 12:18
von EyDu
@Gerold
Das sieht ja mal hübsch aus, kannte ich noch gar nicht. Mal wieder was dazu gelernt :)

Verfasst: Freitag 23. November 2007, 17:09
von Holzdolph
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()

Verfasst: Freitag 23. November 2007, 17:23
von Leonidas
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'

Verfasst: Freitag 23. November 2007, 19:43
von Y0Gi
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'

Verfasst: Freitag 30. November 2007, 10:09
von Holzdolph
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