Moduł `io` w Pythonie
W tym artykule omówiono moduł io w Pythonie.
Wyjaśnimy moduł io w Pythonie na praktycznych przykładach.
YouTube Video
Moduł io w Pythonie
Przetwarzanie wejścia/wyjścia stanowi podstawę wszelkich operacji na danych, takich jak pliki, sieci i standardowe I/O. Moduł io w Pythonie udostępnia zestaw klas abstrakcyjnych, które ujednolicają te operacje wejścia/wyjścia. Kluczową koncepcją do zrozumienia tego modułu jest pojęcie „strumienia”.
Czym jest strumień?
Strumień to abstrakcyjny przepływ do sekwencyjnego i ciągłego odczytu oraz zapisu danych.
Podczas odczytu treści pliku bajt po bajcie lub wysyłania i odbierania danych przez sieć, wszystkie te działania mogą być obsługiwane jako strumienie danych.
Abstrahując ten mechanizm, pliki, pamięć i sieci — różne źródła I/O — mogą być obsługiwane za pomocą wspólnych operacji, takich jak odczyt i zapis.
Moduł io w Pythonie zapewnia jednolity interfejs dla strumieni, umożliwiając wydajne przetwarzanie danych tekstowych i binarnych.
Podstawowa struktura modułu io
Moduł io posiada trójwarstwową hierarchię zgodnie z charakterem strumieni.
-
Warstwa surowa (
RawIOBase)RawIOBaseobsługuje najniższy poziom operacji bajtowych, takich jak deskryptory plików systemu operacyjnego oraz urządzenia. -
Warstwa buforowana (
BufferedIOBase)BufferedIOBasezapewnia bufor, aby zwiększyć wydajność operacji wejścia/wyjścia.BufferedReaderiBufferedWriterto typowe przykłady. -
Warstwa tekstowa (
TextIOBase)TextIOBasekonwertuje sekwencje bajtów na ciągi znaków i obsługuje kodowanie. Zazwyczaj podczas otwierania pliku za pomocą funkcjiopen(), wykorzystywany jestTextIOWrapperz tej warstwy.
Dzięki tej strukturze moduł io wyraźnie rozdziela operacje wejścia/wyjścia tekstowego i binarnego, umożliwiając przy tym elastyczne łączenie ich.
Podstawowa struktura modułu io
RawIOBase zarządza deskryptorami plików na najniższym poziomie, powyżej znajduje się warstwa BufferedIOBase dodająca bufor, a na samej górze TextIOBase odpowiadająca za konwersje na ciągi znaków.
1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())- Ten kod służy do sprawdzenia grupy klas abstrakcyjnych dziedziczących po
IOBase. Można zauważyćTextIOBase,BufferedIOBaseiRawIOBase, potwierdzając tym samym strukturę hierarchiczną.
io.IOBase: Klasa bazowa dla wszystkich
IOBase to abstrakcyjna klasa bazowa dla wszystkich obiektów wejścia/wyjścia, definiująca wspólne metody, takie jak close(), flush(), czy seekable(). Rzadko używa się jej bezpośrednio – najczęściej korzysta się z niej poprzez klasy pochodne.
1import io
2
3f = io.StringIO("data")
4print(f.seekable()) # True
5print(f.readable()) # True
6print(f.writable()) # True
7f.close()- Ten przykład pokazuje, że wspólne metody
IOBasesą również dostępne w klasach wyższego poziomu.seekable()ireadable()są przydatne do sprawdzania właściwości strumienia.
io.RawIOBase: Warstwa najniższego poziomu
RawIOBase to warstwa najbliższa deskryptorom plików systemu operacyjnego i nie wykonuje buforowania. Typową implementacją jest FileIO, który odczytuje i zapisuje dane bajtami.
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()FileIOto konkretna implementacjaRawIOBase; wszystkie operacje odczytu i zapisu odbywają się w postaci obiektówbytes. Wydajność można poprawić, łącząc tę warstwę z wyższą warstwąBufferedIOBase.
io.BufferedIOBase: Warstwa pośrednia (z buforowaniem)
BufferedIOBase to warstwa pośrednia, która buforuje dane, dzięki czemu dostęp do dysku jest bardziej wydajny. Główne implementacje to BufferedReader, BufferedWriter, BufferedRandom i 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'- W tym przykładzie dane zapisane przez
BufferedWritersą tymczasowo przechowywane w buforze pamięci, a rzeczywisty zapis do niższej warstwy następuje po wywołaniuflush().
Przykład użycia BufferedReader
BufferedReader to buforowany strumień tylko do odczytu, który umożliwia wydajne czytanie za pomocą peek() i 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()jedynie podgląda dane bez przesuwania wskaźnika. Łącząc ją zread(), można elastycznie sterować buforowaniem.
io.TextIOBase: Warstwa tekstowa
TextIOBase jest warstwą abstrakcji do obsługi ciągów znaków, która wewnętrznie wykonuje dekodowanie i kodowanie. Typową klasą implementacyjną jest 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'))- W tym przykładzie
TextIOWrapperkoduje ciąg na UTF-8 i zapisuje go do podłożonego strumienia binarnego.
Przykład odczytu przy użyciu TextIOWrapper
Podczas odczytu dekodowanie odbywa się automatycznie.
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'TextIOWrapperpełni rolę podstawowej klasy do operacji wejścia/wyjścia tekstowego i stanowi bazę dla niemal wszystkich wysokopoziomowych operacji na plikach.
io.StringIO: Tekstowy strumień w pamięci
StringIO to klasa pozwalająca obsługiwać ciągi znaków w pamięci tak, jakby były plikami. Przydaje się do testowania I/O i generowania tymczasowych danych.
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'StringIOumożliwia operacje podobne do plikowych bez użycia dysku i jest szeroko wykorzystywany w testach jednostkowych.
io.BytesIO: Binarny strumień w pamięci
BytesIO to klasa pliku w pamięci do obsługi sekwencji bajtów (bytes). Przydaje się w sytuacjach, takich jak przetwarzanie binarne lub kompresja danych, gdy nie chcemy używać plików.
1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read())) # [1, 2, 3]BytesIOma taki sam interfejs jakBufferedIOBasei może być używany jako zamiennik wielu API do obsługi plików.
Strumienie własne (tworzenie oryginalnych klas)
Klasy znajdujące się w module io są rozszerzalne i pozwalają na tworzenie własnych klas strumieni. Poniżej znajduje się przykład podklasy TextIOBase, która podczas zapisu zamienia cały tekst na wielkie litery.
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"- Dopóki przestrzegasz kontraktu
TextIOBase, możesz definiować dowolne niestandardowe zachowania w podobny sposób. Łatwo również rozszerzać strumienie dla konkretnych zastosowań, takich jak pliki czy sieci.
Podsumowanie
Moduł io porządkuje przetwarzanie wejścia/wyjścia w hierarchię klas abstrakcyjnych i konkretnych.
RawIOBaseto klasa do bajtowych operacji na poziomie systemu operacyjnego.BufferedIOBaseto klasa zapewniająca efektywną warstwę buforowania.TextIOBaseto klasa zarządzająca odczytem i zapisem ciągów znaków.StringIOiBytesIOto klasy oferujące strumienie w pamięci.
Zrozumienie tych klas pozwala precyzyjnie pojąć działanie systemu wejścia/wyjścia w Pythonie i stosować je do operacji na plikach, komunikacji sieciowej oraz projektowania strumieni testowych.
Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.