Das `io`-Modul in Python
Dieser Artikel erklärt das io-Modul in Python.
Wir erklären das io-Modul in Python mit praktischen Beispielen.
YouTube Video
Das io-Modul in Python
Die Eingabe-/Ausgabeverarbeitung bildet die Grundlage für alle Arten von Datenoperationen, wie Dateien, Netzwerke und Standard-I/O. Pythons io-Modul stellt eine Reihe von abstrakten Klassen zur Verfügung, die diese Ein- und Ausgabeoperationen vereinheitlichen. Das Schlüsselkonzept zum Verständnis dieses Moduls ist die Idee eines "Streams" (Datenstroms).
Was ist ein Datenstrom?
Ein Stream ist ein abstrakter Datenfluss, der ein sequentielles und kontinuierliches Lesen und Schreiben von Daten ermöglicht.
Beim Lesen von Dateiinhalten Byte für Byte oder beim Senden und Empfangen von Daten über ein Netzwerk können all diese Vorgänge als Datenströme behandelt werden.
Durch die Abstraktion dieses Mechanismus können Dateien, Speicher und Netzwerke – verschiedene I/O-Quellen – mit gemeinsamen Operationen wie Lesen und Schreiben verarbeitet werden.
Das io-Modul von Python bietet ein einheitliches Interface für Streams und ermöglicht so die effiziente Verarbeitung von sowohl Text- als auch Binärdaten.
Grundstruktur des io-Moduls
Das io-Modul besitzt gemäß der Art der Streams eine dreischichtige Hierarchie.
-
Rohe Schicht (
RawIOBase)RawIOBaseverarbeitet die unterste Ebene des Byte-I/O, wie Datei-Deskriptoren des Betriebssystems und Geräte. -
Puffer-Schicht (
BufferedIOBase)BufferedIOBasestellt einen Zwischenspeicher (Buffer) zur Verfügung, um die I/O-Effizienz zu steigern.BufferedReaderundBufferedWritersind typische Beispiele. -
Text-Schicht (
TextIOBase)TextIOBasewandelt Bytesequenzen in Strings um und übernimmt die Kodierung. Normalerweise wird beim Öffnen einer Datei mit der Funktionopen()derTextIOWrapperaus dieser Schicht verwendet.
Dank dieser Struktur trennt das io-Modul Text- und Binär-I/O klar voneinander, während flexible Kombinationen möglich sind.
Grundstruktur des io-Moduls
RawIOBase verarbeitet die Datei-Deskriptoren des Betriebssystems auf der untersten Ebene, BufferedIOBase fügt einen Zwischenspeicher hinzu und die oberste Schicht TextIOBase übernimmt die Umwandlung in Strings.
1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())- Dieser Code dient zur Überprüfung der Gruppe von abstrakten Klassen, die von
IOBaseerben. Sie sehenTextIOBase,BufferedIOBaseundRawIOBase, was die hierarchische Struktur bestätigt.
io.IOBase: Die Basisklasse aller Klassen
IOBase ist die abstrakte Basisklasse für alle I/O-Objekte und definiert gemeinsame Methoden wie close(), flush() und seekable(). Sie wird selten direkt genutzt und üblicherweise über abgeleitete Klassen angesprochen.
1import io
2
3f = io.StringIO("data")
4print(f.seekable()) # True
5print(f.readable()) # True
6print(f.writable()) # True
7f.close()- Dieses Beispiel zeigt, dass die gemeinsamen Methoden von
IOBaseauch in höheren Klassen verwendet werden können.seekable()undreadable()sind nützlich, um die Eigenschaften eines Streams zu prüfen.
io.RawIOBase: Die unterste Schicht
RawIOBase ist die Ebene, die dem Datei-Deskriptor des Betriebssystems am nächsten ist und verzichtet auf Pufferung. Die typische Implementierung ist FileIO, das byteweise liest und schreibt.
1import io, os
2
3# Create a low-level FileIO object (no buffering)
4fd = os.open('raw_demo.bin', os.O_RDWR | os.O_CREAT)
5raw = io.FileIO(fd, mode='w+')
6raw.write(b'abc123')
7raw.seek(0)
8print(raw.read(6)) # b'abc123'
9raw.close()FileIOist eine konkrete Implementierung vonRawIOBase; alle Lese- und Schreibvorgänge erfolgen alsbytes. Die Effizienz kann erhöht werden, indem man sie mit der oberenBufferedIOBase-Schicht kombiniert.
io.BufferedIOBase: Zwischenschicht (mit Pufferung)
BufferedIOBase ist eine Zwischenschicht, die Pufferung durchführt und damit den Festplattenzugriff effizienter macht. Die Hauptimplementierungen sind BufferedReader, BufferedWriter, BufferedRandom und BufferedRWPair.
1import io
2
3# Create a buffered binary stream on top of a BytesIO (simulate file)
4base = io.BytesIO()
5buffered = io.BufferedWriter(base)
6buffered.write(b'Python IO buffering')
7buffered.flush()
8base.seek(0)
9print(base.read()) # b'Python IO buffering'- In diesem Beispiel werden die über
BufferedWritergeschriebenen Daten vorübergehend in einem Speicherpuffer abgelegt und erst beim Aufruf vonflush()tatsächlich an die untere Schicht übergeben.
Beispiel für BufferedReader
BufferedReader ist ein nur lesbarer, gepufferter Datenstrom, der effizientes Lesen mit peek() und read() unterstützt.
1import io
2
3stream = io.BytesIO(b"1234567890")
4reader = io.BufferedReader(stream)
5print(reader.peek(5)) # b'12345' (non-destructive)
6print(reader.read(4)) # b'1234'
7print(reader.read(3)) # b'567'peek()schaut nur "in die Daten hinein" und bewegt den Zeiger nicht. Durch die Kombination mitread()kann man die Pufferung flexibel steuern.
io.TextIOBase: Nur-Text-Schicht
TextIOBase ist eine Abstraktionsschicht zur Verarbeitung von Zeichenfolgen, die intern Dekodierung und Kodierung durchführt. Eine typische Implementierungsklasse ist TextIOWrapper.
1import io
2
3# Wrap a binary stream to handle text encoding
4binary = io.BytesIO()
5text_stream = io.TextIOWrapper(binary, encoding='utf-8')
6text_stream.write("\u3053\u3093\u306B\u3061\u306F")
7text_stream.flush()
8
9# Reset stream position
10binary.seek(0)
11
12# Read bytes once
13data = binary.read()
14
15# Show both raw bytes and decoded text
16print("Raw bytes:", data)
17print("Decoded text:", data.decode('utf-8'))- In diesem Beispiel kodiert
TextIOWrapperdie Zeichenkette in UTF-8 und schreibt sie in den zugrunde liegenden Binär-Stream.
Beispiel für das Lesen mit TextIOWrapper
Beim Lesen erfolgt die Dekodierung automatisch.
1import io
2
3binary_data = io.BytesIO("Python I/O".encode('utf-8'))
4text_reader = io.TextIOWrapper(binary_data, encoding='utf-8')
5print(text_reader.read()) # 'Python I/O'TextIOWrapperdient als grundlegende Klasse für Text-I/O und bildet die Basis für fast alle Dateioperationen auf hoher Ebene.
io.StringIO: Text-Stream im Speicher
StringIO ist eine Klasse, mit der man Zeichenketten im Speicher so behandeln kann, als wären sie Dateien. Sie ist nützlich für I/O-Tests und zur Erzeugung temporärer Daten.
1import io
2
3text_buf = io.StringIO()
4text_buf.write("In-memory text stream")
5text_buf.seek(0)
6print(text_buf.read()) # 'In-memory text stream'StringIOermöglicht dateiähnliche Operationen ohne Festplattenzugriff und wird häufig in Unit-Tests eingesetzt.
io.BytesIO: Binär-Stream im Speicher
BytesIO ist eine im Speicher befindliche Datei-Klasse zur Verarbeitung von Bytesequenzen (bytes). Sie ist nützlich für Situationen wie Binärverarbeitung oder Datenkompression, in denen man keine Dateien verwenden möchte.
1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read())) # [1, 2, 3]BytesIObesitzt das gleiche Interface wieBufferedIOBaseund kann als Ersatz für viele Datei-APIs eingesetzt werden.
Eigene Streams (Erstellung von Originalklassen)
Die Klassen im io-Modul sind erweiterbar, sodass Sie eigene Stream-Klassen erstellen können. Unten finden Sie ein Beispiel für eine TextIOBase-Unterklasse, die beim Schreiben alle Texte in Großbuchstaben umwandelt.
1import io
2
3class UpperTextIO(io.TextIOBase):
4 def __init__(self):
5 self.buffer = ""
6 def write(self, s):
7 self.buffer += s.upper()
8 return len(s)
9
10u = UpperTextIO()
11u.write("hello io")
12print(u.buffer) # "HELLO IO"- Solange Sie den Vertrag von
TextIOBaseeinhalten, können Sie ein beliebiges eigenes Verhalten auf diese Art definieren. Auch die Erweiterung von Streams für spezielle Anwendungen wie Dateien oder Netzwerke ist einfach möglich.
Zusammenfassung
Das io-Modul organisiert die Ein- und Ausgabe in einer Hierarchie aus abstrakten und konkreten Klassen.
RawIOBaseist eine Klasse für Byte-I/O auf Betriebssystemebene.BufferedIOBaseist eine Klasse, die eine effiziente Zwischenspeicherschicht bereitstellt.TextIOBaseist eine Klasse, die das Lesen und Schreiben von Zeichenketten verwaltet.StringIOundBytesIOsind Klassen, die Streams im Speicher bereitstellen.
Wenn Sie diese Klassen verstehen, können Sie die Funktionsweise des Ein-/Ausgabesystems von Python präzise erfassen und auf Dateioperationen, Netzwerkkommunikation und das Design von Test-Streams anwenden.
Sie können den obigen Artikel mit Visual Studio Code auf unserem YouTube-Kanal verfolgen. Bitte schauen Sie sich auch den YouTube-Kanal an.