De `io`-module in Python
Dit artikel legt de io-module in Python uit.
We zullen de io-module in Python uitleggen met praktische voorbeelden.
YouTube Video
De io-module in Python
Invoer/uitvoer-verwerking vormt de basis voor allerlei dataoperaties, zoals bestanden, netwerken en standaard I/O. De io-module van Python biedt een set abstracte klassen die deze invoer/uitvoer-operaties verenigen. Het belangrijkste concept om deze module te begrijpen is het idee van een 'stream'.
Wat is een stream?
Een stream is een abstracte stroom voor het sequentieel en continu lezen en schrijven van data.
Bij het byte voor byte lezen van bestandsinhoud of het verzenden en ontvangen van gegevens via een netwerk, kan dit allemaal worden behandeld als datastromen.
Door dit mechanisme te abstraheren, kunnen bestanden, geheugen en netwerken—verschillende bronnen van I/O—worden behandeld met gemeenschappelijke bewerkingen zoals lezen en schrijven.
De io-module van Python biedt een uniforme interface voor streams, waardoor efficiënte verwerking van zowel tekst als binaire data mogelijk is.
Basisstructuur van de io-module
De io-module heeft een drie-lagen hiërarchie, afhankelijk van het type stream.
-
Ruwe laag (
RawIOBase)RawIOBasebehandelt de laagst-niveau byte I/O, zoals bestandsdescriptors van het besturingssysteem en apparaten. -
Gebufferde laag (
BufferedIOBase)BufferedIOBasebiedt een cache (buffer) om de I/O-efficiëntie te verbeteren.BufferedReaderenBufferedWriterzijn typische voorbeelden. -
Tekstlaag (
TextIOBase)TextIOBasezet byte-reeksen om naar strings en regelt encoding. Meestal wordt bij het openen van een bestand met de functieopen(),TextIOWrapperuit deze laag gebruikt.
Dankzij deze structuur scheidt de io-module tekst- en binaire I/O duidelijk, terwijl flexibele combinaties mogelijk zijn.
Basisstructuur van de io-module
RawIOBase behandelt besturingssysteem-bestandsdescriptors op de onderste laag, met BufferedIOBase die een buffer toevoegt, en de bovenste laag TextIOBase die stringconversies afhandelt.
1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())- Deze code is bedoeld om de groep abstracte klassen die erven van
IOBasete controleren. Je zietTextIOBase,BufferedIOBaseenRawIOBase, waarmee de hiërarchische structuur wordt bevestigd.
io.IOBase: De basisklasse van alles
IOBase is de abstracte basisklasse voor alle I/O-objecten, die gemeenschappelijke methoden zoals close(), flush() en seekable() definieert. Het wordt zelden direct gebruikt en meestal benaderd via afgeleide klassen.
1import io
2
3f = io.StringIO("data")
4print(f.seekable()) # True
5print(f.readable()) # True
6print(f.writable()) # True
7f.close()- Dit voorbeeld toont aan dat de gemeenschappelijke methoden van
IOBaseook in hogere klassen kunnen worden gebruikt.seekable()enreadable()zijn handig om de eigenschappen van een stream te controleren.
io.RawIOBase: De laagste laag
RawIOBase is de laag die het dichtst bij het besturingssysteem-bestandsdescriptor ligt en voert geen buffering uit. De typische implementatie is FileIO, die per byte leest en schrijft.
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()FileIOis een concrete implementatie vanRawIOBase; alle lees- en schrijfoperaties gebeuren alsbytes. De efficiëntie kan worden verbeterd door het te combineren met de bovenliggendeBufferedIOBase-laag.
io.BufferedIOBase: Tussenlaag (met buffering)
BufferedIOBase is een tussenlaag die buffering uitvoert, waardoor schijf-toegang efficiënter wordt. De belangrijkste implementaties zijn BufferedReader, BufferedWriter, BufferedRandom en 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 dit voorbeeld worden gegevens die via
BufferedWriterzijn geschreven tijdelijk in een geheugenbuffer opgeslagen, en worden ze daadwerkelijk naar de onderste laag geschreven bij het aanroepen vanflush().
Voorbeeld van BufferedReader
BufferedReader is een alleen-lezen gebufferde stroom die efficiënt lezen ondersteunt met peek() en read().
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()'gluurt' alleen naar de data en verplaatst de pointer niet. Door het te combineren metread(), kun je buffering flexibel aansturen.
io.TextIOBase: Alleen-tekstlaag
TextIOBase is een abstractielaag voor het verwerken van tekenreeksen, waarbij intern decodering en codering wordt uitgevoerd. Een typische implementatieklasse is 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 dit voorbeeld encodeert
TextIOWrapperde string naar UTF-8 en schrijft deze naar de onderliggende binair-stream.
Voorbeeld van lezen met TextIOWrapper
Decodering wordt automatisch uitgevoerd tijdens het lezen.
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 de basisklasse voor tekst-I/O en vormt de basis voor vrijwel alle bestandsoperaties op hoog niveau.
io.StringIO: In-geheugen tekststream
StringIO is een klasse waarmee je strings in het geheugen kunt behandelen alsof het bestanden zijn. Het is handig voor I/O-testen en tijdelijke gegevensgeneratie.
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'StringIOmaakt bestandsachtige bewerkingen mogelijk zonder de schijf te gebruiken en wordt veel gebruikt bij unittests.
io.BytesIO: In-geheugen binair-stream
BytesIO is een in-geheugen bestandsklasse voor het verwerken van bytereeksen (bytes). Het is handig voor situaties zoals binaire verwerking of gegevenscompressie waarbij je geen bestanden wilt gebruiken.
1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read())) # [1, 2, 3]BytesIOheeft dezelfde interface alsBufferedIOBaseen kan als vervanger worden gebruikt voor veel bestand-API's.
Aangepaste streams (originele klassen maken)
De klassen in io zijn uitbreidbaar, zodat je je eigen streamklassen kunt maken. Hieronder staat een voorbeeld van een TextIOBase-subklasse die alle tekst in hoofdletters omzet bij het schrijven.
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"- Zolang je je houdt aan het contract van
TextIOBase, kun je gedrag naar wens op deze manier definiëren. Het is ook eenvoudig om streams uit te breiden voor specifiek gebruik, zoals bestanden en netwerken.
Samenvatting
De io-module organiseert invoer/uitvoer-verwerking in een hiërarchie van abstracte en concrete klassen.
RawIOBaseis een klasse voor byte-I/O op besturingssysteemniveau.BufferedIOBaseis een klasse die een efficiënte bufferlaag biedt.TextIOBaseis een klasse die het lezen en schrijven van strings aanstuurt.StringIOenBytesIOzijn klassen die in-geheugen streams leveren.
Door deze klassen te begrijpen kun je precies doorzien hoe het I/O-systeem van Python werkt en deze toepassen bij bestandsoperaties, netwerkcommunicatie en het ontwerpen van teststreams.
Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.