Python und Dateien

Dateien sind die einfachste Möglichkeit, Daten dauerhaft zu speichern, wie du das in Python programmatisch machst, zeigt dir dieser Teil der Reihe.

1Python Programmierkurs
2Python: Methoden
3Kontrollstrukturen
4Strings in Python
5Container
6Objekte in Python
7Module
8Exceptions in Python
9Typkonvertierung
10Python und Dateien
11Datum und Zeit mit Python verarbeiten
12Multithreading
13Netzwerk in Python
14Logging in Python
15GPIO
16Automatische Tests
17Datenbanken mit Python
18Python: Generatoren und List Comprehension
19Python: Webseiten mit Flask
20Python virtuelle Umgebungen
21Interrupts & Signale
22NumPy
23Matplotlib
24match
25Reguläre Ausdrücke Python Tutorial Teil 25

Dateien

Letztendlich wird alles in Dateien gespeichert, seinen es Bilder, Briefe, Tabellen oder auch die Konfigurationsdateien in /etc deines Raspberry Pi. Auch Webseiten, die du aufrufst liegen auf dem Server in einer Datei. Sehen wir mal, wie du in Python mit Dateien (oder englisch Files) arbeiten kannst.

Datei erzeugen

Eine Datei wird erzeugt, indem du sie mit der Python Funktion open() öffnest. Die Funktion erwartet zwei Parameter, zum einen den Dateinamen, zum anderen den Modus, in dem die Datei geöffnet werden soll. Sie liefert einen sog. Filehandle zurück, den du in einer Variable ablegen solltest, um in die Datei zu schreiben oder aus ihr zu lesen.

f = open('datei.txt','x')
wschreiben
w+schreiben/lesen, überschreibt bestehende Datei oder legt neue Datei an
wb+wie w+, binär
rlesen
r+lesen und schreiben
rblesend binär Modus
rb+lesend/schreibend binär
aanhängen
a+anhängen und lesen
abanhängen, binär
xexclusive – Datei neu anlegen, Fehler, wenn Datei bereits existiert.

Eine Datei ist eine Abfolge von Bytes auf dem Datenträger. Die Interpretation des Inhalts wird vom jeweiligen Dateiformat vorgeschrieben. Textdateien sind einfache eine Abfolge von Strings, die durch ein Newline ‚\n‘ von einander getrennt sind. Zu den Binärdateien zählen z.B. alle Bilddateien wie JPEG oder PNG, aber auch Videos und Audiofiles. python interpretiert jede Datei standardmäßig als Textdatei, außer, du sagst über den Dateimodus etwas anderes.

in Datei schreiben

Um eine Liste in eine Datei zu schreiben, öffnest du die Datei zunächst im Schreibmodus ‚w‘ iterierst dann über die Liste und schreibst jeden Eintrag mit f.write() in die Datei. Wichtig ist, die Datei am Ende mit f.close() zu schließen, um die Daten aus dem Zwischenspeicher des Betriebssystems wirklich auf den Datenträger zu schreiben.

namen = ['Homer','Marge','Bart','Lisa','Maggie']

f = open('namen.txt','w')

#f.write(namen)
for name in namen:
  f.write(f'{name}\n')

f.close()

Damit wird eine Datei namen.txt erzeugt, die wie folgt aussieht.Beachte, dass ein I/O-Fehler abgefangen wird und das Schließen der Datei im finally Block auf jeden Fall durchlaufen wird.

Homer
Marge
Bart
Lisa
Maggie

Durch den f-String mit LineFeed (\n) wird jeder Name der Liste in eine eigene Zeile geschrieben.

Es gibt einen Kniff, diesen Code kürzer zu halten. Das with Statement öffnet Dateien automatisch und schließt sie zum Ende des Blocks auch automatisch wieder.

from namen import namen


try:
  with open('namen.txt','w') as f:
   for name in namen:
     f.write(f'{name}\n')
except IOError as err:
 print(f'I/O-Fehler {err}')

Du siehst, dass nicht nur das open() weggefallen ist sondern auch der gesamte finally Block.

Datei lesen

Jetzt wollen wir unsere Datei auch wieder einlesen.

namen = []

try:
  f = open('namen.txt','r')
#f = open('namen.txt','r',encoding='utf-8')

  for line in f:
    namen.append(line)
except IOError as x:
  print(f'I/O-Fehler: {x}')
finally:
  if f != None:
    f.close()


print(namen)

Du öffnest die Datei Read-Modus und iterierst danach über jede Zeile in der Datei und fügst die Zeile zur Liste namen dazu. Falls du Umlaute in der Datei hast, benutzt du die auskommentierte open() Zeile, die das Encoding auf ‚UTF-8‘ setzt, dieser Parameter bei open() ist optional. Die Ausgabe sieht dann so aus:

['Homer\n', 'Marge\n', 'Bart\n', 'Lisa\n', 'Maggie\n']

Das ist natürlich unschön bis störend, dass der Zeilenumbruch Teil des Namens ist.Um das zu beheben,musst du die Zeile namen.append() wie folgt ersetzen:

namen.append(line.strip())

Wie du schon gesehen hast, entfernt die strip()– Methode Leerzeichen und Zeilenumbruchzeichen am Stringende. Dadurch stehen dann nur noch die Namen ohne Zeilenvorschub in der Liste.

Kommaseparierte Dateien

Eines der einfachsten Verfahren, Daten strukturiert zu speichern, sind kommaseparierte Dateien (engl.: commaseperated values, CSV). In diesen Dateien werden tabellarische Daten gespeichert, jede Spalte der Tabelle wird mit Kommata voneinander getrennt, jede Tabellenzeile ist eine Zeile in der CSV Datei. im Repository ist die Datei namen.csv hinterlegt.

Skinner,Seymour
Largo,Dewey
Krabappel,Edna
Hoover,Elisabeth
Chalmers,Gary

Jetzt geht’s darum, diese Datei einzulesen und zu verarbeiten

school = []
class Lehrer():

  def __init__(self, vorname, name):
    self.vorname = vorname
    self.name  = name

  def __str__(self):
    return f'{self.vorname} {self.name}'


try:

  with open('namen.csv','r') as f:
   for line in f:
     splitted = line.strip().split(',')
     name = splitted[0]
     vorname = splitted[1]

     lehrer = Lehrer(vorname,name)
     school.append(lehrer)


except IOError as x:
  print(f'I/O-Fehler: {x}')

print(school)
print(school[0])
print(school[3])

Nach dem Entfernen des LineFeed mittels strip(), wird die gelesene Zeile mittels split() in seine einzelnen Werte aufgeteilt. split() liefert eine Liste der Werte in der Zeile zurück, genau an den Kommata aufgetrennt. Da wir wissen, dass der Nachname in jeder Zeile der erste Wert ist, können wir ihn mit name = splitted[0] auslesen. Ebenso der vorname als zweiten Wert. Die Gefahr bei CSV Dateien liegt darin, dass die Datei nicht exakt so strukturiert ist, wie es dass Programm vorgibt. Die Folge ist dann meist ein unkontrollierter Programmabbruch und Verarbeitungsfehler. In unserem kleinen Beispiel besteht die Gefahr nicht und wir bauen mit vorname und name pro Zeile in der CSV-Datei eine Instanz der Klasse Lehrer auf und fügen diese der Liste school dazu.

XML lesen

Neben der nicht selbsterklärenden Struktur einer CSV-Datei gibt es bei CSV meist auch noch das Problem mit Werten, die das Trennsymbol enthalten (bspw. Beträge mit Nachkommastellen). Diese dann korrekt zu verarbeiten erfordert u.U. einigen Aufwand.

Mit XML (eXtensible Markup Language) wurde ein Dateiformat geschaffen, dass diese Probleme behebt. Die Struktur ist sowohl für Menschen als auch für Computerprogramme verständlich. Letztlich basiert XHTML, das die Struktur von Webseiten beschreibt, auch auf XML.

In der Datei school.xml habe ich die obige CSV Datei als XML hinterlegt.

<schule>
<lehrerliste>
 <lehrer>
   <name>Skinner</name>
   <vorname>Seymore</vorname>
 </lehrer>
 <lehrer>
  <name>Largo</name>
  <vorname>Dewey</vorname>
 </lehrer>
 <lehrer>
   <name>Krabappel</name>
   <vorname>Edna</vorname>
 </lehrer>
 <lehrer>
   <name>Hoover</name>
   <vorname>Elisabeth</vorname>
 </lehrer>
 <lehrer>
   <name>Chalmers</name>
   <vorname>Garry</vorname>
 </lehrer>
</lehrerliste>
</schule>

Um die Datei zu verarbeiten, benötigen wir einen Parser. Zu unserem Glück bringt Python diesen bereits mit und wir müssen ihn nur noch importieren und benutzen.

import xml.etree.ElementTree as ET

Wir importieren die Klasse ElementTree des Package xml.etree und können sie unter dem Namen ET im Programm ansprechen.

Diese Klasse stellt uns alles zur Verfügung, was das syntaktische Parsen der XML-Datei angeht. Um die smantische Auswertung müssen wir und selbst kümmern. Zunächst lesen wir die Datei ein und erhalten so einen Baum des Markups.

tree = ET.parse('./school.xml')
root = tree.getroot()

In tree ist jetzt der gesamte geparste Baum der XML-Struktur eingelesen, root enthält des Wurzelelement ( in unserer Datei <schule>). Um über die Liste der <lehrer> Elemente zu iterieren, lassen wir uns diese von root geben:

for item in root.findall('lehrerliste/lehrer'):

Die findall() Methode liefert uns alle Elemente im Wurzelelement zurück, die im Knoten „lehrerliste“ liegen und ein <lehrer> Element sind. Innerhalb von item liefert uns die find() Methode die Elemente für <name> und <vorname>

  vorname = item.find('vorname').text
  name = item.find('name').text

Im text Attribut findest du dann die Werte für Namen und Vornamen.
Der komplette Code sieht dann so aus:

import xml.etree.ElementTree as ET

class Lehrer():
  def __init__(self, vorname,name):
    self.vorname = vorname
    self.name = name

  def __str__(self):
    return f'{self.vorname} {self.name}'

school = []


tree = ET.parse('./school.xml')
root = tree.getroot()

print(f'{tree}')
print(f'{root}')
for item in root.findall('lehrerliste/lehrer'):
  vorname = item.find('vorname').text
  name = item.find('name').text
  print(f'item = {item}, {vorname} {name}')
  school.append(Lehrer(vorname, name))

print()
print(school)
print(school[0])
print(school[3])

JSON lesen

Das Einlesen einer JSON-Datei (JavaScript Object Notation) sieht ziemlich ähnlich aus.
Zunächst die Datei school.json mit den Datensätzen:

{
 "lehrerliste": [

    {
      "name": "Skinner",
      "vorname": "Seymore"
    },
    {
      "name": "Largo",
      "vorname": "Dewie"
    },
    {
      "name": "Krabappel",
      "vorname": "Edna"
    },
    {
      "name": "Hoover",
      "vorname": "Elisabeth"
    }

  ]
}

Das passende Programm sieht dem von XML sehr sehr ähnlich.

import json

json = json.loads(open('./school.json').read())

class Lehrer():
  def __init__(self, vorname,name):
    self.vorname = vorname
    self.name = name

  def __str__(self):
    return f'{self.vorname} {self.name}'

school = []

liste = json['lehrerliste']

for item in liste:
  name = item['name']
  vorname = item['vorname']

  school.append(Lehrer(vorname,name))

print()
print(school)
print(school[0])
print(school[3])

Das soll unseren Ausflug in die Dateien erstmal abschließen. Als Nächstes wollen wir mal auf Datumsangaben schauen.

Schreibe einen Kommentar

Cookie Consent Banner von Real Cookie Banner