Modulet `io` i Python

Modulet `io` i Python

Denne artikel forklarer io-modulet i Python.

Vi vil forklare io-modulet i Python med praktiske eksempler.

YouTube Video

Modulet io i Python

Input/output-behandling danner grundlaget for alle former for dataoperationer, såsom filer, netværk og standard I/O. Pythons io-modul tilbyder et sæt abstrakte klasser, der forener disse input/output-operationer. Nøglebegrebet for at forstå dette modul er idéen om en "stream" (strøm).

Hvad er en strøm?

En strøm er en abstrakt strømning til sekventiel og kontinuerlig læsning og skrivning af data.

Når man læser filer byte for byte eller sender og modtager data over et netværk, kan alt dette behandles som datastrømme.

Ved at abstrahere denne mekanisme, kan filer, hukommelse og netværk – forskellige I/O-kilder – håndteres med fælles operationer som læsning og skrivning.

Pythons io-modul giver et samlet interface for strømme, hvilket muliggør effektiv håndtering af både tekst og binære data.

Grundlæggende struktur af io-modulet

io-modulet har et trelags hierarki afhængigt af streamens natur.

  1. Rå lag (RawIOBase)

    RawIOBase håndterer den laveste niveau byte-I/O, såsom OS filbeskrivere og enheder.

  2. Bufferlag (BufferedIOBase)

    BufferedIOBase tilbyder en cache (buffer) for at forbedre I/O-effektiviteten. BufferedReader og BufferedWriter er typiske eksempler.

  3. Tekstlag (TextIOBase)

    TextIOBase konverterer bytesekvenser til strenge og håndterer kodning. Normalt bruges TextIOWrapper fra dette lag, når man åbner en fil med funktionen open().

Takket være denne struktur adskiller io-modulet tydeligt tekst- og binær-I/O, samtidig med at det giver fleksible kombinationer.

Grundlæggende struktur af io-modulet

RawIOBase styrer OS-filbeskrivere på det nederste lag, BufferedIOBase tilføjer en cache ovenpå, og toplaget TextIOBase håndterer strengkonverteringer.

1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())
  • Denne kode bruges til at tjekke gruppen af abstrakte klasser, der nedarver fra IOBase. Du kan se TextIOBase, BufferedIOBase og RawIOBase, hvilket bekræfter hierarkiets struktur.

io.IOBase: Basisklassen for alle

IOBase er den abstrakte basisklasse for alle I/O-objekter og definerer fælles metoder såsom close(), flush() og seekable(). Den bruges sjældent direkte og tilgås normalt via afledte klasser.

1import io
2
3f = io.StringIO("data")
4print(f.seekable())   # True
5print(f.readable())   # True
6print(f.writable())   # True
7f.close()
  • Dette eksempel viser, at de fælles metoder fra IOBase også kan bruges i overklasser. seekable() og readable() er nyttige til at kontrollere egenskaberne for en strøm.

io.RawIOBase: Det laveste niveau lag

RawIOBase er laget tættest på OS-filbeskriveren og udfører ikke buffering. Den typiske implementering er FileIO, som læser og skriver pr. byte.

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()
  • FileIO er en konkret implementering af RawIOBase; alle læsninger og skrivninger udføres som bytes. Effektiviteten kan øges ved at kombinere den med det øvre BufferedIOBase-lag.

io.BufferedIOBase: Mellemlag (med buffering)

BufferedIOBase er et mellemlag, der udfører buffering og gør diskadgang mere effektiv. De vigtigste implementeringer er BufferedReader, BufferedWriter, BufferedRandom og 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'
  • I dette eksempel lagres data skrevet via BufferedWriter midlertidigt i en hukommelsesbuffer og overføres faktisk til det nedre lag, når flush() kaldes.

Eksempel på BufferedReader

BufferedReader er en skrivebeskyttet buffret strøm, som understøtter effektiv læsning med peek() og 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() 'kigger' kun på dataen og flytter ikke pegeren. Ved at kombinere det med read(), kan du fleksibelt styre buffering.

io.TextIOBase: Tekst-only lag

TextIOBase er et abstraktionslag til håndtering af strenge, som internt udfører dekodning og kodning. En typisk implementeringsklasse er 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'))
  • I dette eksempel koder TextIOWrapper strengen til UTF-8 og skriver den til den underliggende binære strøm.

Eksempel på læsning med TextIOWrapper

Dekodning udføres automatisk ved læsning.

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'
  • TextIOWrapper fungerer som grundklassen for tekst-I/O og danner basis for næsten alle filoperationer på højt niveau.

io.StringIO: Tekststrøm i hukommelsen

StringIO er en klasse, der lader dig håndtere strenge i hukommelsen, som om de var filer. Den er nyttig til I/O-testning og midlertidig datagenerering.

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'
  • StringIO muliggør fil-lignende operationer uden brug af disk og anvendes ofte i enhedstest.

io.BytesIO: Binær strøm i hukommelsen

BytesIO er en hukommelsesfilklasse til håndtering af bytesekvenser (bytes). Den er nyttig ved binærbehandling eller datakomprimering, hvor man ikke ønsker at bruge filer.

1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read()))  # [1, 2, 3]
  • BytesIO har samme interface som BufferedIOBase og kan bruges som en erstatning for mange fil-API'er.

Brugerdefinerede strømme (oprettelse af egne klasser)

Klasserne i io er udvidelige, så du kan oprette dine egne streamklasser. Nedenfor er et eksempel på en TextIOBase-underklasse, der gør al tekst versal ved skrivning.

 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"
  • Så længe du følger kontrakten for TextIOBase, kan du definere enhver brugerdefineret funktionalitet som dette. Det er også nemt at udvide strømme til specifikke formål, såsom filer og netværk.

Sammendrag

io-modulet organiserer input/output-behandling i et hierarki af abstrakte og konkrete klasser.

  • RawIOBase er en klasse til OS-niveau byte-I/O.
  • BufferedIOBase er en klasse, der tilbyder et effektivt cache-lag.
  • TextIOBase er en klasse, der håndterer læsning og skrivning af strenge.
  • StringIO og BytesIO er klasser, der tilbyder hukommelsesstrømme.

Forståelse af disse klasser gør dig i stand til nøjagtigt at forstå, hvordan Pythons I/O-system fungerer, og anvende dem til filoperationer, netværkskommunikation samt design af teststrømme.

Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.

YouTube Video