.. include:: markup.rst **************** Datenspeicherung **************** Es gibt eine :mark:`Reihe von Möglichkeiten` wie man Daten speichern kann. Welche Methode am besten ist, :mark:`hängt von Kriterien ab` wie: * Datentyp * Datenmenge * Zugriffsgeschwindigkeit * Erweiterbarkeit * Implementierungsaufwand vs. Nutzen Tabellenformate =============== CSV / Text Format ----------------- Ein sehr verbreitetes :mark:`Import- und Exportformat für Datenbanken` und :mark:`Tabellenkalkulationen` ist das CSV-Format (Comma Separated Values). CSV-Dateien sind Textdateien, die zeilenweise Datensätze enthalten welche mit :mark:`Trennzeichen` (``,``, ``;``, ...) versehen sind z.B.: :: Marke;Modell;Leistung Porsche;911;350 Skoda;Octavia;140 Audi;Q3;110 Dabei ist die erste Zeile die :mark:`Datenbezeichnung`. Solche Daten können mit unterschiedlichsten Softwareapplikationen erzeugt werden. Die :mark:`einfachste Möglichkeit` aus Python Daten zu schreiben, ist unter ":ref:`Daten in eine Datei schreiben`" erläutert d.h. mittels ``for`` und ``print`` Statement. Eine solche Datei kann mit dem Python ``csv`` Modul eingelesen werden: :: In [1]: import csv In [2]: with open("daten.csv", "r") as csvfile: ...: reader = csv.reader(csvfile, delimiter=";") ...: for row in reader: ...: print(row) ...: ['Marke', 'Modell', 'Leistung'] ['Porsche', '911', '350 '] ['Skoda', 'Octavia', '140 '] ['Audi', 'Q3', '110 '] bzw. wieder in eine Datei geschrieben werden: :: In [3]: with open("test_daten.csv", "w", newline='') as csvfile: ...: writer = csv.writer(csvfile, delimiter=';') ...: writer.writerow(['Marke', 'Modell', 'Leistung']) ...: daten = ( ['Porsche', '911', '350 '], ...: ['Skoda', 'Octavia', '140 '], ...: ['Audi', 'Q3', '110 ']) ...: writer.writerows(daten) Anmerkungen: * Mit ``"wb"`` statt ``"w"`` kann man :mark:`Binärfiles` schreiben (mit ``"rb"`` wieder lesen). * für korrekte Zeilenendungen auf unterschiedlichen Plattformen wird ``newline=''`` empfohlen. (siehe https://docs.python.org/3/library/csv.html#id3) * Es können Files geschrieben werden, welche direkt von Microsoft :mark:`EXCEL gelesen werden` können (einfach anklicken im Explorer). XLSX Format ----------- Weit verbreitet ist das Microsoft :mark:`XLSX File Format`. Mit dem Modul ``openpyxl`` lassen sich diese Files direkt schreiben (siehe Beispiel ``daten_xlsx.py``). .. literalinclude:: src/daten_xlsx.py .. figure:: images/excel2.png :scale: 70 % :align: center Das :mark:`Lesen` von XLSX ist wesentlich aufwendiger aufgrund von "Merged Cells", Formeln, etc. und wird hier nicht näher behandelt. Ein einfaches Beispiel dazu (siehe ``daten_xlsx2.py``): .. literalinclude:: src/daten_xlsx2.py Python Pandas ------------- Hat man :mark:`große numerische Datenmengen` welche manipuliert und analysiert werden, ist Python `Pandas `_ die richtige Bibliothek. Vereinfacht gesprochen steht dahinter ein sehr effizientes Tabellenformat mit vielen Analyse- und Visualisierungfunktionen. .. figure:: images/pandas.png :scale: 50 % :align: center Beispielsweise können sehr einfach ``xlsx`` Daten gelesen und verarbeitet werden (Fortsetzung des oberen Beispiels): :: In [1]: import pandas as pd In [2]: meineAutos = pd.read_excel('daten.xlsx', sheet_name='Meine Autos') In [3]: print(meineAutos) Marke Modell Leistung 0 Porsche 911 350 1 Skoda Octavia 140 2 Audi Q3 110 In [4]: print(meineAutos.values) [['Porsche' '911' 350] ['Skoda' 'Octavia' 140] ['Audi' 'Q3' 110]] XML Dateien =========== Das :mark:`CSV Format` ist * einfach lesbar, aber * nicht einfach erweiterbar und wartbar. Alternative: Das :mark:`XML Format` (Extensible Markup Language). Dieses Format ist : * eine hierarchisch aufgebaute Datenstruktur (erweiterbar), welche * in einem lesbaren Textformat verfasst ist. Für das obige Beispiel würde ein XML File so aussehen (``daten.xml``): :: Porsche 911 350 Skoda Octavia 140 Audi Q3 110 Man bezeichnet diese Datenstruktur als :mark:`Document Object Model` (DOM). Die Abbildung `XML DOM Baum`_ zeigt die grafische Darstellung. .. _`XML DOM Baum`: .. figure:: images/dom.png :scale: 80 % :align: center Beispiel eines XML DOM Baumes Erklärung: * Der Baum besteht aus :mark:`Elementen`. * Übergeordnete heißen :mark:`Parents`, untergeordnete :mark:`Childs` und jene auf der gleichen Ebene :mark:`Siblings`. * Auf der untersten Ebene werden die Daten als :mark:`Text` gespeichert. Das Lesen/Schreiben kann mit folgenden Python Modulen implementiert werden: * ``xml.dom.minidom`` Document Object Model, kurz DOM (liest alles in Speicher) * ``xml.sax`` Simple API for XML, kurz SAX (liest fortlaufend in Speicher) * ``xml.etree.ElementTree``, einfacher als die beiden anderen, i.A. ausreichend. Hier ein Beispiel (``daten_xml_elementtree.py``) mit ``xml.etree.ElementTree``: .. literalinclude:: src/daten_xml_elementtree.py Ausgabe: :: Porsche 911 350 Skoda Octavia 140 Audi Q3 110 Für Genaueres zu diesem Thema wird auf die Literatur verwiesen. Datenbanken =========== :mark:`Große bzw. komplexe Datenmengen` benötigen entsprechende :mark:`Verwaltungsprogramme`. Obige Konzepte sind dafür nur bedingt geeignet. Man verwendet daher :mark:`Datenbanken`. Bei einer Datenbank wird zwischen dem Programm und dem Massenspeicher (Festplatte, ..) ein Zwischenlayer (:mark:`Datenbanksystem`) eingeführt (siehe Abbildung `Datenbankschnittstelle`_). .. _`Datenbankschnittstelle`: .. figure:: images/datenbank.png :scale: 80 % :align: center Datenbankschnittstelle Allgemeines: * Das Datenbanksystem nimmt dabei Abfragen, sogenannte :mark:`Queries` (Anfragen) entgegen und gibt Datensätze zurück. * Für Abfragen von relationalen Datenbanken wurde die :mark:`Sprache SQL` (Structured Query Language) entwickelt. * :mark:`Python` stellt die Module ``mySQLdb`` und ``sqlite3`` zur Verfügung um via SQL mit einer Datenbank zu kommunizieren. .. Objektspeicherung - pickle ========================== Das Modul :mark:`pickle` bietet komfortable Funktionen für das :mark:`Abspeichern von Objekten`. Aus dem Objekt wird ein :mark:`String` erzeugt welcher einfach :mark:`abgespeichert und eingelesen` werden kann. Beispiel Objekt speichern: :: >>> import pickle >>> f = open("test_pickle.txt", "w") >>> pickle.dump([1, 2, 3], f) Beispiel Objekt einlesen: :: >>> import pickle >>> f = open("test_pickle.txt") >>> pickle.load(f) [1, 2, 3] .. Datenbanken =========== :mark:`Große bzw. komplexe Datenmengen` benötigen entsprechende :mark:`Verwaltungsprogramme`. Obige Konzepte sind dafür nur bedingt geeignet. Man verwendet daher :mark:`Datenbanken`. Bei einer Datenbank wird zwischen dem Programm und dem Massenspeicher (Festplatte, ..) ein Zwischenlayer (:mark:`Datenbanksystem`) eingeführt (siehe Abbildung `Datenbankschnittstelle`_). .. _`Datenbankschnittstelle`: .. figure:: images/datenbank.png :scale: 80 % :align: center Datenbankschnittstelle Allgemeines: * Das Datenbanksystem nimmt dabei Abfragen, sogenannte :mark:`Queries` (Anfragen) entgegen und gibt Datensätze zurück. * Hier verwenden wir :mark:`relationale Datenbanken`, die einen Datenbestand in Tabellen organisieren. * Für Abfragen von relationalen Datenbanken wurde die :mark:`Sprache SQL` (Structured Query Language) entwickelt. * :mark:`Python` stellt die Module ``mySQLdb`` und ``sqlite3`` zur Verfügung um via SQL mit einer Datenbank zu kommunizieren. Im Folgen werden wir ein einfaches Beispiel mit ``sqlite3`` machen. Datenbank – sqlite3 ------------------- SQLite ist ein sehr :mark:`einfaches Datenbanksystem` und in Python integriert. Hier ein Beispiel (``daten_sqlite3.py``, Daten von oben): .. literalinclude:: src/daten_splite3.py Ausgabe: :: [(u'Porsche', u'911'), (u'Skoda', u'Octavia'), (u'Audi', u'Q3')] Erklärungen: * Im Allgemeinen laufen Datenbanken auf einem :mark:`Server` und ein :mark:`Client` muss sich mit diesem verbinden. ``sqlite3`` emuliert dieses Verhalten. Daher macht man zuerst ein ``connect`` zur Datenbasis. * Um mit der Datenbank arbeiten zu können, braucht es einen sogenannte :mark:`Cursor` (Positionsanzeiger), analog zu einem Textverarbeitungsprogramm. * Mit ``execute`` werden :mark:`SQL Befehle` abgesetzt. Alle großgeschriebenen Wörter sind Bestandteile der Sprache SQL. * Werte können mit :mark:`Wildcards` (``?``) von Variablen übergeben werden. * Die Werte befinden sich zunächst im Arbeitsspeicher, erst mit ``commit`` werden diese in die Datenbank geschrieben. * Für die :mark:`Datenbankabfrage` wird der SQL Befehl ``SELECT`` verwendet.