Hallo zusammen. Ich habe folgendes Problem. Ich möchte alle im Verzeichnis vorhandene CSV Datei lesen, diese bearbeiten und dann in ein anderes Verzeichnis abspeichern. Kann mir da jemand helfen?
from sys import exit
import os
import csv
import datetime
from pathlib import Path
#from pprint import pprint
from tkinter import filedialog
#import tkinter.messagebox
now = datetime.datetime.now()
# Define some fixed strings
fixed_four_dot_zero = '.4,0'
fixed_uni = 'Universität Regensburg;Unistr. 31;93053;Regensburg;Warenannahme'
fixed_100_percent = '100.00'
fixed_nineteen = '19.00'
fixed_stk = 'Stk'
fixed_email = 'email@ur.de'
fixed_Sachbearbeiter = '13866'
# empty output, will be written to file
output = []
skipped = 0
output_row = []
#-------Such aus dem Verzeichnis alle CSV Datein-------#
directory = os.path.join("/sdcard/Python/Tkinterdb")
for root,dirs,files in os.walk(directory):
for file in files:
if file.endswith(".csv"):
filename1 = open(file,"r")
print(file)
@pUC19: Warum kaperst Du einen Thread zu einem ganz andren Thema, statt einen neuen aufzumachen?
Warum importierst Du pathlib und nutzt es dann gar nicht? Statt Strings mit split und + zu verarbeiten solltest du dir das csv-Modul anschauen. Das Encoding Deiner Inputdatei stimmt nicht.
Und weil ist jetzt Deine konkrete Frage? Was genau tut nicht so wie Du willst?
@pUC19: Bei den Import-Zeilen ist jede zweite Zeile eine die etwas importiert was gar nicht verwendet wird. Nettes Muster. Absicht? Warum?
Wobei mir scheint, dass das `csv`-Modul sinnvoll wäre wenn man es denn tatsächlich benutzen würde.
Auf Modulebene solle nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Konstanten werden per Konvention KOMPLETT_GROSS geschrieben. Das betrifft die ganzen `fixed_*`-Namen am Anfang. Wobei man dann in Frage stellen sollte was der `fixed_`-Präfix bedeuten soll. Das sich die Werte nicht ändern, also die Namen nicht an andere Werte gebunden werden sollen? Das wird ja dann schon durch die Schreibweise als Konstante deutlich. Genau deswegen macht man das ja so.
`fixed_nineteen` kommt mir als Name komisch vor. Das ist doch hoffentlich nicht der Mehrwertsteuersatz? Wenn sich der ändert, muss man ja beides anpassen, den Wert und den Namen. Das macht irgendwie den Vorteil von einer Konstanten zunichte das man im Falle einer Änderung nur eine Stelle im Programm anpassen muss. Bei Namen ist ja für den Leser interessant was der Wert dahinter bedeutet, nicht das man den Wert selbst noch mal im Namen wiederholt.
`output`, `output_row`, und `skipped` werden nur ein einziges mal initialisiert für alle Dateien die da verarbeitet werden. Das ist ziemlich sicher falsch.
`os.path.join()` mit nur einem Argument macht keinen Sinn. Den Basispfad würde man auch besser als Konstante definieren, denn das ist auch eine Information die man nur an einer Stelle im Code haben möchte, um sie leicht anpassen zu können. In neuem Code würde ich das gleich als `Path`-Objekt machen.
Nachdem klar ist, dass es sich um einen Dateinamen handelt der mit ".csv" endet wird es ziemlich wirr und ich denke dieser ganze Code lief nie auch nur ansatzweise. Du nennst den Dateinamen `file` und das Dateiobjekt dann `filename1` — warum auch immer da eine sinnlose 1 dran hängt ist das extrem verwirrend die Objekte genau entgegengesetzt dem zu bennenen was sie eigentlich sind.
Und dann nennst Du eine Zeichenkettendarstellung eines Dateiobjekts `input_file_name` was weder Sinn macht — mit der Zeichenkettendarstellung eines Dateiobjekts kann man nichts sinnvolles machen — noch inhaltlich zu dem Namen passt.
Dann wird auf den Pfadnamen auf den schon mal sinnlos `os.path.join()` angewendet wurde, noch mal sinnlos `os.path.join()` angewendet. Der Name an den das Ergebnis gebunden wird, wird aber danach nirgends mehr verwendet. Warum also überhaupt diese Zeile?
Danach wird dann das gleiche Dateiobjekt wieder in eine Zeichenkette umgewandelt und an den Namen `output_file_name` gebunden. Wir haben dann also die gleiche sinnfreie Zeichenkette an die Namen `input_file_name` und `output_file_name` gebunden. Selbst wenn das Dateiobjekte wären kann eine Textdatei nicht gleichzeitig Ein- und Ausgabedatei sein, ausser in recht exotischen Sonderfällen, nämlich wenn sich an den Zeilenlängen nichts ändert. Und man muss die Datei dann auch in einem entsprechenden Modus öffnen. Aber wie gesagt, das geht sowieso nicht wirklich im allgemeinen Fall.
Die Dateien die da geöffnet werden, werden in dem Code nirgends geschlossen. Du baust da auf das implizite Schliessen wenn die Speicherbereinigung das Dateiobjekt abräumt, da gibt es aber keine Zusagen *wann* das passiert. Falls es also genug Dateien gibt, kann man so die Anzahl der Dateihandles die das Betriebssystem dem Prozess zugesteht aufbrauchen und das Programm bricht deswegen mit einem Fehler ab. Wo möglich sollte man die ``with``-Anweisung verwenden um die Ressource Datei zu verwalten. Beim schreiben machst Du das ja auch.
Bei Textdateien sollte man immer explizit eine Kodierung beim öffnen angeben. Auch das machst Du beim Schreiben, aber nicht beim Lesen.
Namen sollte man nicht zu weit von der Verwendung an Namen binden. `csv_output_file` wird sehr weit von der Stelle entfernt definiert an der es dann letztendlich verwendet wird. Es wird sogar definiert wenn es am Ende gar nicht verwendet wird.
Man kann an dem fehlerhaften Code jetzt nicht erkennen wie die Zieldatei genau heissen soll, aber es wäre besser wenn die nicht auf ".csv" endet weil das Zielverzeichnis in dem Verzeichnis liegt welches das Programm rekursiv nach ".csv"-Dateien durchsucht. Das findet dann ja auch Dateien die es selbst gerade eben dort abgelegt hat oder in einem früheren Durchlauf. Da bekommt man dann Probleme wenn versucht wird eine verarbeitete Datei noch mal zu verarbeiten.
`enumerate()` zu verwenden um die erste Zeile anders als die anderen zu behandeln ist wahrscheinlich nicht sinnvoll. Aus dem Code wird nicht klar was da tatsächlich passieren soll, weil das alles nicht wirklich Sinn ergibt, aber meistens kann man die erste Zeile einfach vor der Schleife behandeln.
Falls der Code bis in die letzte Zeile der Schleife kommt, ist da ein offensichtlicher `NameError` weil `outpit` nicht definiert ist.
`list()` mit `output` und `row` aufzurufen macht keinen Sinn. Das sind bereits Listen, wobei ``for`` ja noch nicht einmal eine Liste braucht.
Wenn man sich das Schreiben anschaut, dann macht `output_row()` davor keinen Sinn, selbst wenn diese Liste nicht nur immer grösser und grösser werden würde mit jeder Eingabezeile ehthält die ja nicht eine Zeile sondern mehrere.
Es liegt in der Herangehensweise IMHO schon ein Problem. Das ist ein riesiger Haufen Code am Stück an dem viel zu viel nicht funktioniert. Soweit sollte es bei der Programmentwicklung gar nicht erst kommen. Man zerlegt das Problem in Teilprobleme und die wieder in Teilprobleme, solange bis man einzelne Teilprobleme mit jeweils einer Funktion mit ein paar Zeilen Code lösen kann. Das macht man dann und testet die Funktion/Teillösung ob sie das tut was sie soll. Und man macht erst mit der nächsten Funktion weiter wenn das der Fall ist. So setzt man dann nach und nach die Teillösungen zu grösseren Teillösungen zusammen, bis man das Gesamtproblem gelöst hat. Auf die Weise hat man immer funktionsfähigen Code oder zumindest welchen bei dem immer nur ein kleiner Teil ungetestet und fehlerbehaftet ist.
Eine Grundaufteilung die sich oft anbietet ist Eingabe, Verarbeitung, und Ausgabe zu trennen. Also beispielsweise eine Funktion die eine Datei in eine geeignete Datenstruktr lädt. Eine Funktion die aus der Struktur eine erstellt die sich zum Schreiben in die Ergebnisdatei eignet. Und eine Funktion, welche die Ergebnisdatenstruktur dann in eine Datei schreibt. Diese drei Funktionen kann man dann in einer Funktion verwenden die eine Datei umwandelt.
Das umwandeln von Eingabedatensätzen in Ausgabedatensätze kann man in der Regel auf das Umwandeln *eines* Eingabedatensatzes in *einen* Ausgabedatensatz herunterbrechen. Wenn man so eine Funktion hat die *einen* Datensatz umwandelt, kann man diese Funktion einfach nacheinander auf alle Eingabedatensätze anwenden.
Das Ermitteln der Dateien die verarbeitet werden müssen kann man auch in eine Funktion stecken.
Für den Anfang lieber ein paar Funktionen zu viel als zu grosse Funktionen die man irgendwann nicht mehr beherrscht/überblickt. Kleine Funktionen die getestet sind, also funktionieren, zusammenfassen, ist einfacher als sich mit wachsenden Funktionen herumzuschlagen und die in Kleinere aufzuteilen.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Hi, vielen Dank für die Verbesserungsvorschläge. Ich wusste nicht, wie ich ein neues Thema eröffnen, daher habe ich ein ähnliches genommen.
Der Python Code an sich habe ich viele Male umgeändert. Ursprüngliche lief er als tkinter und hat auch das gemacht was es soll. Des wegen sind in dem Code noch Elemente enthalten, die nicht dazu gehören. Sorry. Selber bin ich nur ein Anfänger und habe die Aufgabe, dieses Programm bis Mittwoch fertig zustellen.
@blackjack: Ich werde mich heute dran machen alle deine Ansätze abzuarbeiten. Vielen lieben Dank.