Werte in csv Datei einschreiben

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
sportgangg
User
Beiträge: 4
Registriert: Dienstag 3. April 2012, 19:20

Hallo zusammen,
Ich habe mal ne Frage betreffend das einschreiben von vorher definierten Werten ,welche aus verschiedenen .out Dateien stammen.
In meinem Fall wären das die Parameter:
MDNBR,Heat Flux,Axial Location , Subchannel und Rod .Jeweils für die Stellen A und B
Jede .out Datei hat jeweils genau einen Wert für jeden Parameter....
Nun habe ich folgendes Problem:Ich habe folgendes Skript geschrieben das funktioniert auch ganz gut soweit ,nur schreibt es mir wenn ich mehrere .out Dateien habe leider nur einen Wert in meine csv Datei.Wenn ich sie mit print ausgeben lasse zeigt es mir jedoch mehrere Werte an.
Wie programmiere ich es denn so,dass alle werte ins csv file geschrieben werden?

Code: Alles auswählen

#!/usr/bin/python


from numpy import *
import os

folderpath ="/home/georg/Auswertungen/out/"
filepathlist =os.listdir(folderpath)
print filepathlist

for file in filepathlist:
    if file.endswith('.out'):
       f = open(folderpath + file, 'r')
       count_row = 0 

       for row in f:
           count_row = count_row + 1
           row_string_list = row.split() 
           length = len(row_string_list)
    
           if row_string_list[0:4] == ['Summary', 'of', 'CHF', 'Data']:
              row_number_CHF_Data = count_row
#              print row_number_CHF_Data 
#              print row_string_list 
       f.close()

       f = open(folderpath+'/'+file, 'r')
       r = open('test.csv', 'w')
       count_row = 0 

       for row in f:
           count_row = count_row + 1
           row_string_list = row.split() 
           length = len(row_string_list)
        
           if count_row == row_number_CHF_Data + 81:
              MDNBR_B =row_string_list[len(row_string_list)-3]
              Heat_Flux_B=row_string_list[len(row_string_list)-4]
              Axial_Location_B=row_string_list[len(row_string_list)-5]
              Rod_B=row_string_list[len(row_string_list)-2]
              Subchannel_B=row_string_list[len(row_string_list)-1]
#             print row_string_list
#              print MDNBR_B
              print Heat_Flux_B
#              r.writelines(Heat_Flux_B)
#             print Axial_Location_B
#             print Rod_B
#             print Subchannel_B
           if count_row == row_number_CHF_Data + 93:
              MDNBR_A=row_string_list[len(row_string_list)-3]
              Heat_Flux_A=row_string_list[len(row_string_list)-4]
              Axial_Location_A=row_string_list[len(row_string_list)-5]
              Rod_A=row_string_list[len(row_string_list)-2]
              Subchannel_A=row_string_list[len(row_string_list)-1]
#             print row_string_list
#              print MDNBR_A
#             print Heat_Flux_A
#             print Axial_Location_A
#             print Rod_A
#             print Subchannel_A
       r.write(str(Heat_Flux_B))
       f.close()
       r.close()
Grüße
Zuletzt geändert von Anonymous am Mittwoch 4. April 2012, 00:58, insgesamt 1-mal geändert.
Grund: Code-Tags hinzugefügt
lunar

@sportgangg: Bitte verwende in Zukunft Code-Tags, damit man Deinen Quelltext auch lesen kann.
BlackJack

@sportgangg: Das Problem liegt beim `open()`. Der Modus 'w' bedeutet „Öffne eine neue, leere Datei zum Schreiben”. Wenn eine mit dem gleichen Namen schon existiert(e), ist deren Inhalt so natürlich verloren. Du möchtest Daten an eine vorhandene Datei anhängen. Dafür ist der 'a'-Modus (wie „append”) vorgesehen. Oder Du öffnest die Datei einmal ausserhalb der Schleife zum schreiben.

Wenn Du mit CSV-Daten arbeiten willst, solltest Du Dir auch mal das `csv`-Modul aus der Standardbibliothek anschauen.

Sternchenimporte sollte man vermeiden, weil dann sehr schnell nicht mehr nachvollziehbar ist, wo welcher Name her kommt. Ausserdem scheint auch gar nichts aus `numpy` verwendet zu werden!?

Pfadnamen sollte man mit `os.path.join()` und nicht mit ``+`` zusammen setzen. In Deinem Fall wäre das `glob`-Modul sehr nützlich.

Dateien sollte man mit der ``with``-Anweisung öffnen. Dann braucht man sie nicht explizit schliessen, kann sich aber sicher sein, dass sie in jedem Fall wieder geschlossen werden, egal auf welche Weise der Code-Block verlassen wird.

Einbuchstabennamen sind ausser bei den üblichen Schleifenzählern für ganze Zahlen (`i`, `j`, `n`, `m`, …) oder wenn sie auf kompakte Ausdrücke wie „list comprehensions” oder Generatorausdrücke beschränkt sind, keine gute Idee. Namen sollten dem Leser vermitteln wofür ein Objekt im Quelltext steht. In der Regel bedeutet das auch, dass der Typ nicht in den Namen gehört (`row_string_list`), weil der sich eventuell im Laufe der Entwicklung ändern kann, und dann muss man entweder den Namen überall anpassen, oder man hat irreführende Namen im Quelltext stehen. `f` könnte man zum Beispiel `lines` nennen und `row_string_list` könnte man `parts` nennen oder `row` und das was Du `row` nennst dafür `line`.

Statt `count_row` manuell zu führen, sollte man die `enumerate()`-Funktion verwenden.

Du weist `length` an zwei Stellen einen Wert zu, der aber nirgends verwendet wird.

Muss man um die Startzeile zu finden, diese tatsächlich in ihre Bestandteile zerlegen? Würde ein ``line.startswith('Summary of CHF Data')`` nicht eindeutig sein?

Ausdrücke wie ``sequence[len(sequence) - n]`` sind unnötig kompliziert weil ein einfacher negativer Index das gleiche bewirkt.

Was soll der `str()`-Aufruf beim Schreiben von `Heat_Flux_B` bewirken?

Da die beiden extrahierten Zeilen gleich behandelt werden und sich die Namen nur durch einen Zusatz unterscheiden, sollte man hier vielleicht keine Einzelnamen verwenden, sondern eine Liste an die man die Werte der beiden Zeilen anhängt.

Und wenn die Zeilennummer grösser als die für den zweiten Wertesatz wird, könnte man die Schleife abbrechen, denn die Zeilen danach interessieren ja nicht weiter.

Deine Einrückung und die Leerzeichensetzung bei Zuweisungen weicht vom PEP 8 -- Style Guide for Python Code ab. Insbesondere bei der Einrückung sollte man sich an die vier Leerzeichen pro Ebene halten, sonst wird es kompliziert Quelltext mit anderen auszutauschen. Wenn man es wie Du innerhalb des eigenen Quelltextes nicht *einheitlich* macht, kann es auch bei eigenem Quelltext problematisch werden Quelltext an andere Stellen zu verschieben oder in andere Skripte zu übernehmen.

Dann wären wir bei so etwas (ungetestet):

Code: Alles auswählen

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


def main():
    folder_path = '/home/georg/Auswertungen/out/'
    # 
    # Offsets of the two lines of interest relative to the start of
    # the CHF data.
    # 
    offset_a, offset_b = 81, 93
    # 
    # Offsets of MDNBR, heat flux, axial location, rod, and subchannel
    # within a row.
    # 
    value_offsets = [-3, -4, -5, -2, -1]
    
    with open('test.csv', 'w') as result_file:
        writer = csv.writer(result_file, delimiter=';')
        for path in glob(os.path.join(folder_path, '*.out')):
            # 
            # Get start line of the last CHF data summery in the file.
            # 
            with open(path, 'r') as lines:
                chf_data_offset = None
                for i, line in enumerate(lines):
                    if line.startswith('Summary of CHF Data'):
                        chf_data_offset = i
                assert chf_data_offset is not None, 'No CHF data found.'
            # 
            # Extract the two rows and write them into the result CSV file.
            # 
            with open(path, 'r') as lines:
                offsets = [
                    chf_data_offset + offset_a, chf_data_offset + offset_b
                ]
                result = list()
                for i, line in enumerate(lines):
                    if i in offsets:
                        row = line.split()
                        result.append([row[n] for n in value_offsets])
                    elif i > offsets[-1]:
                        break
                assert len(result) == 2, 'Premature end of file'
                writer.writerows(result)


if __name__ == '__main__':
    main()
Das ist von der Länge und Komplexität für meinen Geschmack schon hart an der Grenze für eine einzige Funktion. Ich würde hier wohl schon mindestens die Verarbeitung einer Einzeldatei in eine eigene Funktion auslagern.

Von der Effizienz her wäre es übrigens ungünstig wenn es nur einen einzigen 'Summary of CHF Data' pro `*.out`-Datei gäbe, denn dann müsste man in der ersten Schleife gar nicht die komplette Datei durchsuchen, sondern könnte nach dem ersten Fund abbrechen. Man müsste nicht mal die Datei zweimal öffnen, sondern könnte nach dem Fund der Startzeile die entsprechende Anzahl von Folgezeilen überlesen, bis man jeweils bei den Interessanten angekommen ist. In dem Fall könnte das so oder so ähnlich aussehen (ungetestet — insbesondere die Offset-Werte könnten hier um eine Zeile daneben liegen):

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import csv
import os
from glob import glob
from itertools import dropwhile, islice
from operator import itemgetter


def main():
    folder_path = '/home/georg/Auswertungen/out/'
    # 
    # Offsets of the two lines of interest relative to the start of
    # the CHF data.
    # 
    offset_a, offset_b = 81, 93
    # 
    # Gets MDNBR, heat flux, axial location, rod, and subchannel
    # from a row.
    # 
    get_values = itemgetter([-3, -4, -5, -2, -1])
    
    with open('test.csv', 'w') as result_file:
        writer = csv.writer(result_file, delimiter=';')
        for path in glob(os.path.join(folder_path, '*.out')):
            with open(path, 'r') as lines:
                chf_lines = dropwhile(
                    lambda line: not line.startswith('Summary of CHF Data'),
                    lines
                )
                writer.writerows(
                    [
                        get_values(islice(chf_lines, n, n + 1).next().split())
                        for n in [offset_a, offset_b - offset_a]
                    ]
                )


if __name__ == '__main__':
    main()
sportgangg
User
Beiträge: 4
Registriert: Dienstag 3. April 2012, 19:20

Hallo nochmal zusammen,
Ersteinmal ein herzliches Dankeschön an BlackJack für deine sehr ausführliche Antwort.Wirklich sehr freundlich von dir!
@linar Sorry kommt nicht mehr vor
Ich werde deine Vorschläge berücksichtigen ,bzw werde sie berücksichtigen.
Klar innerhalb gibt es einige ungereimtheiten wie beispielsweise das importieren von numpy; das dachte ich brauche ich später noch die Konvertierung str() war nur innerhalb meines amateurhaften Debuggings da ,klar die ist unnötig.
Nun aber zur eigentlichen Frage :
Ds mit 'a' für append hatte ich auch schon probiert das funktioniert genauso nicht .In die Datei wird nur 1 Wert geschrieben.Zur Verdeutlichung:
Jede .out datei hat 1 Wert für Heat _Flux B.
Für x .out Dateien gibt es also x Werte für Heat Flux _B.Mein Programm schreibt leider nur den jeweils ersten wert der ersten .out Datei in die Datei.
Mmg bricht die Ausleseschleife ab, bzw sie funktioniert gar nicht??? :roll:
Wäre super wenn mir nochmal jemand hilft
Grüße
P.S @BlackJack Dein Programm hab ich ausprobiert es bricht ab weil es den String nicht findet->No CHF Data found...
Ich würde die .out Dateien anhängen aber ich glaub ich darf das nicht...
BlackJack

@sportgangg: Wie sieht denn so eine 'Summary of CHF Data'-Zeile aus? Ist da vielleicht noch ”whitespace” vor dem 'Summary' oder zwischen den Worten? Kommt die Ausnahme bei meinem Quelltext schon bei der ersten ``*.out``-Datei? Dein Quelltext ist nämlich so geschrieben, dass es gar nicht zwingend auffallen würde, wenn das nicht in jeder '*.out'-Datei vorkommt, solange es nur in der ersten Datei steht. Denn danach ist `row_number_CHF_Data` auf jeden Fall an eine Zahl gebunden — nur dass die eben nicht zur aktuellen Datei passen muss, sondern auch von einem vorherigen Schleifendurchlauf sein kann. Deshalb prüfe ich das explizit.

Dein Quelltext müsste mit 'a' als Modus aus dem selben Grund auch auf jeden Fall in jedem Schleifendurchlauf etwas in die Ausgabedatei schreiben, denn wenn `Heat_Flux_B` einmal etwas zugewiesen wurde, dann bleibt der Wert ja gebunden, auch wenn in der zweiten Schleife nichts neues daran gebunden wird. Deine Werte landen dabei übrigens alle nebeneinander geklebt in einer Zeile.
sportgangg
User
Beiträge: 4
Registriert: Dienstag 3. April 2012, 19:20

@BlackJack
Habs gerade gesehen die Summary of CHF data zeile hat davor einige whitespaces
Aber dank dir für deine Mühe habe es hinbekommen
Grüße
Antworten