@@ -0,0 +1,404 @@ | |||
{ | |||
"cells": [ | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"# Software Entwicklung \n", | |||
"\n", | |||
"## Kapitel 9: IO\n", | |||
"\n", | |||
"Unter *IO* (Input/Output) versteht man alle Mechanismen,\n", | |||
"die mit dem Ausleiten von Daten aus einem Programm\n", | |||
"bzw. dem Einlesen von Daten in ein Programm zusammenhängen." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"### 9.1 Zeichenkodierung\n", | |||
"\n", | |||
"Möchte ein Programm Daten senden (z.B. in eine Datei\n", | |||
"oder über eine Netzwerkverbindung) oder diese empfangen,\n", | |||
"werden letztendlich Bytes übertragen. Handelt es sich bei den\n", | |||
"Daten um Text - also lesbare Zeichen - so muss durch eine\n", | |||
"Zeichenkodierung (engl. *encoding*) festgelegt werden,\n", | |||
"wie dieser Text auf Bytes abgebildet wird.\n", | |||
"\n", | |||
"Ein sehr übliches Kodierungsschema ist *UTF-8*. Darin werden\n", | |||
"die Zahlen 0 bis 127 analog zum alten ASCII-Standard\n", | |||
"insbesondere für grundlegende lateinische Zeichen in\n", | |||
"Groß- und Kleinschrift verwendet. Alle übrigen Zeichen wie\n", | |||
"z.B. deutsche Umlaute, chinesische Schriftzeichen,\n", | |||
"Emojis etc. werden durch größere Zahlen ggf. mit mehreren\n", | |||
"Bytes codiert. Die Zuordnung der Zahlen zu den Zeichen\n", | |||
"ist durch den [*Unicode*-Standard](http://www.unicode.org/)\n", | |||
"festgelegt." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Möchte man eine Python-Zeichenkette in eine Unicode-Bytefolge\n", | |||
"übertragen, so kann dafür die Methode <code>encode</code> der Klasse\n", | |||
"*str* (String) verwendet werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"text = \"Nürnberg ist schön\"\n", | |||
"print(f\"Länge {len(text)}\")\n", | |||
"utf8 = text.encode(\"utf-8\")\n", | |||
"print(utf8)\n", | |||
"print(f\"Länge {len(utf8)}\")" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "-" | |||
} | |||
}, | |||
"source": [ | |||
"Das vorangestellte <code>b</code> signalisiert, dass es sich\n", | |||
"hier um eine Bytefolge handelt." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"print(type(utf8))" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Eine solche Bytefolge kann auch wieder in einen\n", | |||
"Textstring verwandelt werden. Dazu besitzt die\n", | |||
"Klasse *bytes* die Methode <code>decode</code>." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"decoded_text = utf8.decode(\"utf-8\")\n", | |||
"print(decoded_text)\n", | |||
"print(f\"Länge {len(decoded_text)}\")\n" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"### 9.2 Dateien\n", | |||
"\n", | |||
"Unter *Textdateien* verstehen wir Dateien, die\n", | |||
"mit einem Texteditor erzeugt und bearbeitet werden können.\n", | |||
"Der Inhalt sind lesbare Zeichen, die meist\n", | |||
"in Zeilen organisiert sind. Um sie auf einem\n", | |||
"Speichermedium abzulegen, müssen die Zeichen\n", | |||
"in Bytes konvertiert bzw. beim Lesen\n", | |||
"rückübertragen werden.\n", | |||
"\n", | |||
"*Binärdateien* sind Dateien, für die keine Kodierung\n", | |||
"stattfinden soll (z.B. Bilder).\n", | |||
"\n", | |||
"Python besitzt bereits im Standard Funktionen, Klassen und Methoden,\n", | |||
"die das Lesen und Schreiben von Dateien sowie das Übertragen\n", | |||
"von Text in Bytes (und zurück) unterstützen." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Einstiegspunkt ist die Built-In-Funktion <code>open</code>, die ein\n", | |||
"Dateiobjekt zurückliefert. Die Parameter von <code>open</code> sind\n", | |||
"der *Dateiname* (ggf. inkl. Pfad) und der *Bearbeitungsmodus*\n", | |||
"sowie weitere, weniger gebräuchliche optionale Parameter.\n", | |||
"\n", | |||
"\n", | |||
"| *Bearbeitungsmodus* | *Bedeutung* |\n", | |||
"|:--------------------:|----------------------------------------------------|\n", | |||
"| 'r' | Die Datei wird gelesen (muss bereits existieren) |\n", | |||
"| 'w' | Die Datei wird geschrieben (vorhandene Datei wird überschrieben) |\n", | |||
"| 'a' | Die Datei wird geschrieben (neuer Inhalt wird angehängt) |\n", | |||
"| 'r+' | Die Datei wird gelesen und geschrieben |\n", | |||
"\n", | |||
"Standardmäßig finden die Lese- und Schreiboperationen mit der Standard-Kodierung des verwendeten Betriebssystems statt. Soll die Kodierung unterbleiben, muss an den Bearbeitungsmodus ein <code>'b'</code>\n", | |||
"(für binär) angehängt werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "-" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"f = open(\"091a Textdatei\", \"r\")" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Das auf diese Weise erhaltene Dateiobjekt kann für (je nach\n", | |||
"Bearbeitungsmodus) für das Lesen und Schreiben benutzt werden.\n", | |||
"Die Methode <code>read</code> ohne Angabe eines Parameter\n", | |||
"liest den gesamten Inhalt der Datei ein\n", | |||
"(Vorsicht: nur bei kleinen Dateien ratsam, da speicherintensiv)." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"content = f.read()\n", | |||
"print(content)" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Jedes geöffnete Dateiobjekt muss auch wieder geschlossen werden,\n", | |||
"da andernfalls Betriebssystemressourcen dauerhaft belegt bleiben." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"print(f.closed)\n", | |||
"f.close()\n", | |||
"print(f.closed)" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Sollte eine Textdatei in einer anderen Kodierung als die Standard-Kodierung vorliegen, kann die gewünschte Kodierung mittels des Parameters <code>encoding</code> angegeben werden. Mit <code>encoding=None</code> wird wieder die Standard-Kodierung gewählt, was dem Standardwert und damit dem Weglassen des Parameters entspricht. Im folgenden Beispiel wird eine Textdatei geladen, die im UTF-8-Format vorliegt. Die Standard-Kodierung auf Windows weicht allerdings davon ab, wie man an den Umlauten erkennen kann." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": {}, | |||
"outputs": [], | |||
"source": [ | |||
"f = open(\"utf8_text\", \"r\", encoding=None)\n", | |||
"content = f.read()\n", | |||
"print(content)\n", | |||
"f.close()" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"### 9.3 Kontextmanager\n", | |||
"\n", | |||
"Die strenge Verpflichtung, jede Datei auch zu schließen, ist\n", | |||
"gelegentlich nicht einfach zu erfüllen. Falls z.B. eine\n", | |||
"Exception auftritt und die Abarbeitungsreihenfolge\n", | |||
"abgebrochen wird, ist trotzdem *close* aufzurufen." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "-" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"try:\n", | |||
" f = open(\"091a Textdatei\", \"r\")\n", | |||
" z = 1 / 0\n", | |||
" # f.close() würde nicht erreicht!\n", | |||
"except:\n", | |||
" print(\"Fehler!\")\n", | |||
"finally:\n", | |||
" f.close()\n", | |||
"print(f.closed)" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Python bietet für dieses Problem den *Kontextmanager* an. Er\n", | |||
"initialisiert einen *Kontext* für ein Objekt, führt einen\n", | |||
"Codeblock in diesem Kontext aus und räumt beim Verlassen\n", | |||
"des *Kontext* belegte Ressourcen auf.\n", | |||
"\n", | |||
"Das Schlüsselwort für den Beginn eines *Kontext* ist <code>with</code>." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"091a Textdatei\", \"r\") as f:\n", | |||
" print(f.read())\n", | |||
" print(f.closed)\n", | |||
"\n", | |||
"print(f.closed)" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Wie ist das realisiert? Tatsächlich nutzt der\n", | |||
"*Kontextmanager* die beiden *dunder*-Methoden\n", | |||
"<code>\\_\\_entry\\_\\_</code> und <code>\\_\\_exit\\_\\_</code>.\n", | |||
"Die Methode <code>\\_\\_entry\\_\\_</code> wird beim Betreten des\n", | |||
"Kontext aufgerufen, die Methode <code>\\_\\_exit\\_\\_</code> beim\n", | |||
"Verlassen oder beim Auftreten einer nicht behandelten Exception.\n", | |||
"\n", | |||
"Beim Datei-Objekt von Python wird in der\n", | |||
"<code>\\_\\_exit\\_\\_</code>-Methode sichergestellt, dass die\n", | |||
"Datei geschlossen wird.\n", | |||
"\n", | |||
"Durch Überschreiben der Methoden können auch eigene Klassen\n", | |||
"sinnvoll mit einem *Kontextmanager* zusammenarbeiten.\n", | |||
"\n", | |||
"\n" | |||
] | |||
} | |||
], | |||
"metadata": { | |||
"celltoolbar": "Slideshow", | |||
"kernelspec": { | |||
"display_name": "Python 3 (ipykernel)", | |||
"language": "python", | |||
"name": "python3" | |||
}, | |||
"language_info": { | |||
"codemirror_mode": { | |||
"name": "ipython", | |||
"version": 3 | |||
}, | |||
"file_extension": ".py", | |||
"mimetype": "text/x-python", | |||
"name": "python", | |||
"nbconvert_exporter": "python", | |||
"pygments_lexer": "ipython3", | |||
"version": "3.9.9" | |||
} | |||
}, | |||
"nbformat": 4, | |||
"nbformat_minor": 1 | |||
} |
@@ -0,0 +1,9 @@ | |||
1. Zeile | |||
2. Zeile | |||
3. etwas längere Zeile | |||
4. Zeile - hört das nie auf? | |||
5. Zeile - langsam wird es langweilig | |||
6. Zeile | |||
7. Zeile | |||
8. Zeile | |||
9. letzte Zeile |
@@ -0,0 +1,215 @@ | |||
{ | |||
"cells": [ | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"# Software Entwicklung \n", | |||
"\n", | |||
"## Kapitel 9: IO\n", | |||
"\n", | |||
"### 9.4 Dateien lesen\n", | |||
"\n", | |||
"Bei großen Dateien sollte vom vollständigen Einlesen mittels\n", | |||
"<code>read</code> Abstand genommen werden, weil dann\n", | |||
"der gesamte Dateiinhalt im Speicher gehalten werden muss.\n", | |||
"Vielmehr sollte in diesem Fall der Inhalt sukzessive eingelesen\n", | |||
"werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Zu diesem Zweck kann <code>read</code> mit einem Parameter\n", | |||
"aufgerufen werden, der die maximale Anzahl Bytes angibt,\n", | |||
"die gelesen werden sollen." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"091a Textdatei\", \"r\") as f:\n", | |||
" block_size = 10\n", | |||
" block = f.read(block_size)\n", | |||
"\n", | |||
" while len(block)>0:\n", | |||
" print(block, end='*')\n", | |||
" block = f.read(block_size)" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Man kann sich das schrittweise Einlesen der Datei mit Hilfe\n", | |||
"eines Schreib-/Lesekopfs vorstellen, der sich\n", | |||
"entlang eines Stroms von Bytes bzw. Zeichen bewegt.\n", | |||
"Jeder Lesevorgang bewegt den Kopf um die Anzahl der\n", | |||
"gelesenen Zeichen vorwärts. Die Position des Kopfs\n", | |||
"innerhalb der Datei kann mittels <code>tell</code>\n", | |||
"ermittelt werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"091a Textdatei\", \"r\") as f:\n", | |||
" block_size = 10\n", | |||
" block = f.read(block_size)\n", | |||
"\n", | |||
" while len(block)>0:\n", | |||
" print(block, end='')\n", | |||
" pos = f.tell()\n", | |||
" print(f\"<{pos}>\", end='')\n", | |||
" block = f.read(block_size)" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Die Position des Schreib-/Lesekopfs lässt sich auch\n", | |||
"durch die Methode <code>seek</code> verändern." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"091a Textdatei\", \"r\") as f:\n", | |||
" f.seek(110)\n", | |||
" print(f.read())" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Textdateien sind i.d.R. in Zeilen aufgeteilt, die jeweils\n", | |||
"mit einem Zeilenendezeichen abschließen. Die Methode\n", | |||
"<code>readline</code> liest aus einer Textdatein\n", | |||
"die Daten bis zum nächsten Zeilenende." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"091a Textdatei\", \"r\") as f:\n", | |||
" line = f.readline()\n", | |||
" while len(line)>0:\n", | |||
" print(line, end='')\n", | |||
" line = f.readline()" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Diese häufig benötigte Variante des Lesens einer Textdatei\n", | |||
"kann in Python auch mittels einer <code>for</code>-Schleife\n", | |||
"realisiert werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"091a Textdatei\", \"r\") as f:\n", | |||
" for line in f:\n", | |||
" print(line, end='')" | |||
] | |||
} | |||
], | |||
"metadata": { | |||
"celltoolbar": "Slideshow", | |||
"kernelspec": { | |||
"display_name": "Python 3 (ipykernel)", | |||
"language": "python", | |||
"name": "python3" | |||
}, | |||
"language_info": { | |||
"codemirror_mode": { | |||
"name": "ipython", | |||
"version": 3 | |||
}, | |||
"file_extension": ".py", | |||
"mimetype": "text/x-python", | |||
"name": "python", | |||
"nbconvert_exporter": "python", | |||
"pygments_lexer": "ipython3", | |||
"version": "3.9.9" | |||
} | |||
}, | |||
"nbformat": 4, | |||
"nbformat_minor": 1 | |||
} |
@@ -0,0 +1,160 @@ | |||
{ | |||
"cells": [ | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"# Software Entwicklung \n", | |||
"\n", | |||
"## Kapitel 9: IO\n", | |||
"\n", | |||
"### 9.4 Dateien schreiben\n", | |||
"\n", | |||
"Voraussetzung dafür, dass in eine Datei geschrieben werden kann,\n", | |||
"ist ein passender Bearbeitungsmodus." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"093a Textdatei\", \"w\") as f:\n", | |||
" f.write(\"Nürnberg ist schön!\")\n", | |||
"\n", | |||
"with open(\"093a Textdatei\", \"r\") as f:\n", | |||
" print(f.read())" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Wird der Schreib-/Lesekopf zurückgesetzt, kann der bestehende Inhalt überschrieben werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"093a Textdatei\", \"w\") as f:\n", | |||
" f.write(\"Nürnberg ist nice!\")\n", | |||
" pos = f.tell()-5\n", | |||
" f.seek(pos)\n", | |||
" f.write(\"schön!\")\n", | |||
"\n", | |||
"with open(\"093a Textdatei\", \"r\") as f:\n", | |||
" print(f.read())" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Durch den Bearbeitungsmodus <code>'r+'</code> ist es auch\n", | |||
"möglich, mit einem Datei-Objekt zu lesen und zu schreiben." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"093a Textdatei\", \"r+\") as f:\n", | |||
" f.write(\"Nürnberg ist nice!\")\n", | |||
" pos = f.tell()-5\n", | |||
" f.seek(pos)\n", | |||
" f.write(\"schön!\")\n", | |||
" f.seek(0)\n", | |||
" print(f.read())" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Anders als bei <code>print</code> wird bei <code>write</code>\n", | |||
"kein Zeilenwechsel angehängt; es muss also ggf. selbst\n", | |||
"hinzugefügt werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"with open(\"093a Textdatei\", \"r+\") as f:\n", | |||
" f.write(\"Zeile 1\")\n", | |||
" f.write(\"Zeile 2\\n\")\n", | |||
" f.write(\"Zeile 3\\n\")\n", | |||
" f.seek(0)\n", | |||
" print(f.readline())" | |||
] | |||
} | |||
], | |||
"metadata": { | |||
"celltoolbar": "Slideshow", | |||
"kernelspec": { | |||
"display_name": "Python 3 (ipykernel)", | |||
"language": "python", | |||
"name": "python3" | |||
}, | |||
"language_info": { | |||
"codemirror_mode": { | |||
"name": "ipython", | |||
"version": 3 | |||
}, | |||
"file_extension": ".py", | |||
"mimetype": "text/x-python", | |||
"name": "python", | |||
"nbconvert_exporter": "python", | |||
"pygments_lexer": "ipython3", | |||
"version": "3.9.9" | |||
} | |||
}, | |||
"nbformat": 4, | |||
"nbformat_minor": 1 | |||
} |
@@ -0,0 +1,108 @@ | |||
{ | |||
"cells": [ | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"\n", | |||
"Gegeben ist eine binäre Grafikdatei <code>ohm.png</code>." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"from IPython.display import Image\n", | |||
"Image(filename=\"ohm.png\")" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"_Aufgabe 1_\n", | |||
"\n", | |||
"Erstellen Sie ein Python-Programm, dass diese Datei in eine zweite\n", | |||
"Datei <code>logo.png</code> kopiert. Übertragen Sie die Daten bitte\n", | |||
"in 32 Byte Paketen." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": {}, | |||
"outputs": [], | |||
"source": [] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"from IPython.display import Image\n", | |||
"\n", | |||
"\n", | |||
"with open(\"ohm.png\", \"rb\") as source_file:\n", | |||
" with open(\"logo.png\", \"wb\") as dest_file:\n", | |||
" buffer_size = 32\n", | |||
" buffer = source_file.read(buffer_size)\n", | |||
" while len(buffer)>0:\n", | |||
" dest_file.write(buffer)\n", | |||
" buffer = source_file.read(buffer_size)\n", | |||
"\n", | |||
"\n", | |||
"Image(filename=\"logo.png\")" | |||
] | |||
} | |||
], | |||
"metadata": { | |||
"celltoolbar": "Slideshow", | |||
"kernelspec": { | |||
"display_name": "Python 3 (ipykernel)", | |||
"language": "python", | |||
"name": "python3" | |||
}, | |||
"language_info": { | |||
"codemirror_mode": { | |||
"name": "ipython", | |||
"version": 3 | |||
}, | |||
"file_extension": ".py", | |||
"mimetype": "text/x-python", | |||
"name": "python", | |||
"nbconvert_exporter": "python", | |||
"pygments_lexer": "ipython3", | |||
"version": "3.9.9" | |||
} | |||
}, | |||
"nbformat": 4, | |||
"nbformat_minor": 1 | |||
} |
@@ -0,0 +1,186 @@ | |||
{ | |||
"cells": [ | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"# Software Entwicklung \n", | |||
"\n", | |||
"## Kapitel 9: IO\n", | |||
"\n", | |||
"### 9.5 Sockets\n", | |||
"\n", | |||
"So wie der Begriff *Datei* eine griffige Bezeichnung für eine Ansammlung dauerhaft gespeicherter Bytes ist, wird\n", | |||
"mit *Socket* ein Endpunkt für Netzwerkverbindungen bezeichnet.\n", | |||
"Die Kommunikation findet zwischen zwei Sockets *bidirektional* statt, d.h. über jedes Socket können Bytes versendet\n", | |||
"und empfangen werden." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Sockets stehen in Python durch das Standard-Modul <code>sockets</code> zur Verfügung. Wie schon Dateien belegen auch\n", | |||
"Sockets Betriebssystem-Ressourcen, so dass die Verwendung eines Kontextmanagers ratsam ist." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"import socket\n", | |||
"\n", | |||
"with socket.socket() as s:\n", | |||
" pass" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"#### 9.5.1 Client-Server-Modell\n", | |||
"\n", | |||
"Zwar sind bei einer bestehenden Kommunikationsverbindung zwischen zwei Sockets die beiden Sockets prinzipiell\n", | |||
"gleichberechtigt, jedoch gibt es Unterschiede beim Kommunikationsaufbau.\n", | |||
"\n", | |||
"* Ein *Server-Socket* verhält sich passiv, d.h. es wartet auf eingehende Verbindungsanfragen. Trifft eine solche\n", | |||
" ein, generiert es ein weiteres Socket, das fest dieser Verbindung zugeordnet wird und über das die\n", | |||
" anschließende Kommunikation abgewickelt wird. Das *Server-Socket* selbst verbleibt im Wartezustand.\n", | |||
"\n", | |||
"* Ein *Client-Socket* übernimmt den aktiven Part. Es kontaktiert das *Server-Socket* und geht selbst die\n", | |||
" Verbindung mit dem daraufhin bereitgestellten Socket ein." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Die Verbindungsaufnahme folgt einem vorgegebenen Ablauf aus definierten Schritten (auch: *Kommunikationsprimitive*).\n", | |||
"\n", | |||
"![Verbindungsaufnahme mit Kommunkationsprimitiven](../img/Primitive.png \"Kommunikationsprimitive\")" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"#### 9.5.2 Server-Socket\n", | |||
"\n", | |||
"Ein *Server-Socket* ist eindeutig festgelegt durch das Protokoll (z.B. TCP oder UDP), den Rechner\n", | |||
"(z.B. durch dessen IP-Adresse) und eine Portnummer. Letztere dient dazu, dass mehrere Server-Sockets gleichzeitig\n", | |||
"auf einem Rechner existieren können, ohne sich gegenseitig zu beeinflussen.\n", | |||
"\n", | |||
"So gibt es z.B. auf dem Server <code>medinf.efi.th-nuernberg.de</code> mehrere Server-Sockets,\n", | |||
"die permanent angesprochen werden können:\n", | |||
"\n", | |||
"* Port 22: Nimmt Secure-Shell-Anfragen entgegen\n", | |||
"* Port 80: Nimmt HTTP-Anfragen entgegen\n", | |||
"* Port 443: Nimmt HTTPS-Anfragen entgegen" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Das *Server-Socket* wird mit <code>bind</code> an einen bestimmten Port und eine\n", | |||
"IP-Adresse (ggf. hat ein Rechner mehrere IP-Adressen) gebunden. Das Binden schlägt fehl, wenn die\n", | |||
"Kombination bereits von einem anderen Socket belegt ist.\n", | |||
"\n", | |||
"Anschließend beginnt das *Server-Socket* mit <code>listen</code> zu lauschen. Das Primitiv <code>accept</code>\n", | |||
"blockiert den Server, bis ein *Client-Socket* Verbindung aufnimmt. Damit entsteht ein weiteres Socket mit\n", | |||
"einer vom System vergebenen Portnummer, das dediziert nur für die Verbindung mit diesem Client verwendet wird.\n", | |||
"\n", | |||
"Über dieses neue Socket folgen danach Primitive zum Senden\n", | |||
"<code>send</code> und Empfangen <code>receive</code> von Nachrichten. Anzahl und Abfolge sind\n", | |||
"für Sockets nicht festgelegt, müssen aber zwischen Client und Server abgestimmt sein. So legt z.B.\n", | |||
"das auf Sockets aufsetzende Protokoll HTTP fest, dass zunächst eine Nachricht vom Client\n", | |||
"an den Server (*HTTP-Request*) und anschließend eine Nachricht vom Server an den Client\n", | |||
"(*HTTP-Response*) gesendet wird. Während in der ersten Version von HTTP danach die\n", | |||
"Verbindung wieder abgebaut wurde, ist es aktuellen Versionen möglich, dieses Abfolge\n", | |||
"wiederholt über eine bestehende Verbindung abzuwickeln." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Eine etablierte Verbindung ist mit <code>close</code> zu schließen. Bei Verwendung eines\n", | |||
"Kontextmanagers erfolgt dies automatisch.\n", | |||
"\n", | |||
"Auch das *Server-Socket* muss geschlossen werden, um das Binden an einen Port zu beenden\n", | |||
"und den Port freizugeben." | |||
] | |||
} | |||
], | |||
"metadata": { | |||
"celltoolbar": "Slideshow", | |||
"kernelspec": { | |||
"display_name": "Python 3 (ipykernel)", | |||
"language": "python", | |||
"name": "python3" | |||
}, | |||
"language_info": { | |||
"codemirror_mode": { | |||
"name": "ipython", | |||
"version": 3 | |||
}, | |||
"file_extension": ".py", | |||
"mimetype": "text/x-python", | |||
"name": "python", | |||
"nbconvert_exporter": "python", | |||
"pygments_lexer": "ipython3", | |||
"version": "3.9.9" | |||
} | |||
}, | |||
"nbformat": 4, | |||
"nbformat_minor": 1 | |||
} |
@@ -0,0 +1,102 @@ | |||
{ | |||
"cells": [ | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"# Software Entwicklung \n", | |||
"\n", | |||
"## Kapitel 9: IO\n", | |||
"\n", | |||
"### 9.5 Sockets" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"#### 9.5.3 Beispiel für einen Server" | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"import socket\n", | |||
"\n", | |||
"with socket.socket() as server: # Generieren eines Sockets\n", | |||
" host = socket.gethostname() # Die eigene IP-Nummer\n", | |||
" port = 12345 # Festlegen des Ports\n", | |||
" server.bind((host, port)) # Bind\n", | |||
" server.listen() # Listen (blockiert nicht)\n", | |||
" print(\"Ich lausche...\")\n", | |||
"\n", | |||
" for contact in range(0, 10):\n", | |||
" connection, addr = server.accept() # blockiert\n", | |||
" with connection:\n", | |||
" print('Verbindung von ', addr)\n", | |||
" msg = f'Danke für das Vorbeischauen, #{contact+1}!\\n'\n", | |||
" connection.send(msg.encode('utf-8')) # Senden \n", | |||
"\n", | |||
" print(\"Das wars!\")" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Textnachrichten, die über ein Socket versendet werden sollen, müssen in Bytes\n", | |||
"umgewandelt werden.\n" | |||
] | |||
} | |||
], | |||
"metadata": { | |||
"celltoolbar": "Slideshow", | |||
"kernelspec": { | |||
"display_name": "Python 3 (ipykernel)", | |||
"language": "python", | |||
"name": "python3" | |||
}, | |||
"language_info": { | |||
"codemirror_mode": { | |||
"name": "ipython", | |||
"version": 3 | |||
}, | |||
"file_extension": ".py", | |||
"mimetype": "text/x-python", | |||
"name": "python", | |||
"nbconvert_exporter": "python", | |||
"pygments_lexer": "ipython3", | |||
"version": "3.9.9" | |||
} | |||
}, | |||
"nbformat": 4, | |||
"nbformat_minor": 1 | |||
} |
@@ -0,0 +1,146 @@ | |||
{ | |||
"cells": [ | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"# Software Entwicklung \n", | |||
"\n", | |||
"## Kapitel 9: IO\n", | |||
"\n", | |||
"### 9.5 Sockets\n", | |||
"\n", | |||
"#### 9.5.4 Client-Socket\n", | |||
"\n", | |||
"Da das *Client-Socket* den Server kontaktiert, benötigt es die Adresse und den\n", | |||
"Port des *Server-Sockets*. Mit <code>connect</code>\n", | |||
"wird die Verbindung aufgebaut, sofern an der Gegenstelle ein Server\n", | |||
"im Primitiv <code>accept</code> wartet.\n", | |||
"\n", | |||
"Danach folgen Primitive zum Senden\n", | |||
"<code>send</code> und Empfangen <code>receive</code> von Nachrichten\n", | |||
"in einer mit dem Server abgestimmten Reihenfolge.\n", | |||
"\n", | |||
"Abschließend ist die Verbindung mit <code>close</code> zu schließen. Bei Verwendung eines\n", | |||
"Kontextmanagers erfolgt dies automatisch." | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"#### 9.5.5 Beispiel für einen Client" | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"import socket\n", | |||
"\n", | |||
"with socket.socket() as client: # Generieren des Sockets\n", | |||
" host = socket.gethostname() # Server-IP\n", | |||
" port = 12345 # Server-Port\n", | |||
"\n", | |||
" client.connect((host, port)) # Connect\n", | |||
" bytes = client.recv(1024) # Receive\n", | |||
" print (bytes.decode('utf-8'))" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Möchte man ein Socket wie eine Datei behandeln, also statt <code>send</code> und\n", | |||
"<code>recv</code> lieber <code>write</code> und <code>read</code> verwenden, so kann\n", | |||
"mit <code>makefile</code> eine \"Hülle\" um das Socket gelegt werden, die die\n", | |||
"(meisten) Funktionen für Dateien anbietet und übersetzt." | |||
] | |||
}, | |||
{ | |||
"cell_type": "code", | |||
"execution_count": null, | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%%\n" | |||
} | |||
}, | |||
"outputs": [], | |||
"source": [ | |||
"import socket\n", | |||
"\n", | |||
"with socket.socket() as client: # Generieren des Sockets\n", | |||
" host = socket.gethostname() # Server-IP\n", | |||
" port = 12345 # Server-Port\n", | |||
"\n", | |||
" client.connect((host, port)) # Connect\n", | |||
" with client.makefile(encoding=\"utf-8\") as file:\n", | |||
" text = file.readline()\n", | |||
" print (text)" | |||
] | |||
}, | |||
{ | |||
"cell_type": "markdown", | |||
"metadata": { | |||
"pycharm": { | |||
"name": "#%% md\n" | |||
}, | |||
"slideshow": { | |||
"slide_type": "slide" | |||
} | |||
}, | |||
"source": [ | |||
"Textnachrichten, die über ein Socket empfangen werden, müssen aus den übertragenen Bytes\n", | |||
"abgeleitet werden. Nutzt man die Dateischnittstelle, findet die Konvertierung dort statt.\n", | |||
"\n", | |||
" " | |||
] | |||
} | |||
], | |||
"metadata": { | |||
"celltoolbar": "Slideshow", | |||
"kernelspec": { | |||
"display_name": "Python 3 (ipykernel)", | |||
"language": "python", | |||
"name": "python3" | |||
}, | |||
"language_info": { | |||
"codemirror_mode": { | |||
"name": "ipython", | |||
"version": 3 | |||
}, | |||
"file_extension": ".py", | |||
"mimetype": "text/x-python", | |||
"name": "python", | |||
"nbconvert_exporter": "python", | |||
"pygments_lexer": "ipython3", | |||
"version": "3.9.9" | |||
} | |||
}, | |||
"nbformat": 4, | |||
"nbformat_minor": 1 | |||
} |
@@ -0,0 +1,22 @@ | |||
body.rise-enabled div.inner_cell>div.input_area { | |||
font-size: 150%; | |||
} | |||
body.rise-enabled div.output_subarea.output_text.output_result { | |||
font-size: 150%; | |||
} | |||
body.rise-enabled div.output_subarea.output_text.output_stream.output_stdout { | |||
font-size: 150%; | |||
} | |||
body.rise-enabled div.output_subarea.output_html.rendered_html.output_result { | |||
font-size: 150%; | |||
} | |||
body.rise-enabled td { | |||
font-size: 120%; | |||
} | |||
body.rise-enabled th { | |||
font-size: 120%; | |||
} |
@@ -0,0 +1,5 @@ | |||
Zeile 1 | |||
Zeile 2 | |||
Zeile 3 | |||
Zeile 4 Hört das denn nie auf? | |||
Zeile 5 |