Pliki to po prostu napisy ze ścieżką
Większość programów prędzej czy później musi odczytać albo zapisać plik: konfigurację, dane użytkownika, logi, eksport do CSV, mały cache. Python upraszcza to jedną wbudowaną funkcją, open(), oraz blokiem with, który dba o czyste zamknięcie.
Przejdźmy przez typowe przypadki.
Odczyt całego pliku
Najprostszy odczyt:
with open("notes.txt") as f:
contents = f.read()
print(contents)
open("notes.txt") otwiera plik do odczytu (domyślnie). Blok with oznacza, że Python zamknie plik przy wyjściu z bloku, nawet jeśli zostanie zgłoszony wyjątek. Po zamknięciu nie można już używać f, a tekst jest w contents.
contents to jeden napis z całą zawartością pliku. Dobre dla małych plików, złe dla logu o rozmiarze 2 GB.
Odczyt linia po linii
Przy większych plikach iteruj, zamiast wczytywać wszystko do pamięci:
with open("big.log") as f:
for line in f:
if "ERROR" in line:
print(line.strip())
Każda iteracja zwraca jedną linię razem z końcowym znakiem nowej linii, dlatego tak często pojawia się .strip(). Jeśli chcesz listę linii, zrobi to f.readlines(), ale zwykle lepsza jest bezpośrednia iteracja.
Zapis pliku
Aby zapisać, przekaż tryb jako drugi argument:
with open("output.txt", "w") as f:
f.write("first line\n")
f.write("second line\n")
Dwie rzeczy, o których warto pamiętać:
"w"nadpisuje. Jeślioutput.txtjuż istnieje, jego zawartość znika w chwili wykonaniaopen.- Znaki nowej linii musisz dodać samodzielnie.
f.write("hello")zapisuje dokładnie te pięć znaków, bez końcowego znaku nowej linii.
Aby dopisywać zamiast nadpisywać:
with open("output.txt", "a") as f:
f.write("another line\n")
Możesz też zapisać kilka linii naraz przez writelines:
lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
f.writelines(lines)
Ta sama zasada: znaki nowej linii dostarczasz ty.
print do pliku
print ma argument file, co daje łatwy sposób na zapis bez ręcznego dodawania znaków nowej linii:
with open("log.txt", "w") as f:
print("started", file=f)
print("finished", file=f)
Każde print zapisuje swoje argumenty i końcowy znak nowej linii. Przy niezobowiązującym wyjściu to często najwygodniejsza forma.
Tryb tekstowy i binarny
Domyślnie open działa w trybie tekstowym. Python dekoduje bajty na napisy (na współczesnych platformach domyślnie jako UTF-8) i zajmuje się konwersją znaków końca linii.
Obrazy, pliki PDF, pliki skompilowane i wszystko, co nie jest tekstem, otwieraj w trybie binarnym, dodając "b" do trybu:
with open("image.png", "rb") as f:
data = f.read()
print(len(data)) # liczba bajtów
with open("image_copy.png", "wb") as f:
f.write(data)
W trybie binarnym dostajesz obiekty bytes zamiast str, a Python nie rusza znaków końca linii.
Określanie kodowania
Przy plikach tekstowych podawaj kodowanie jawnie. W 2026 roku UTF-8 jest prawie zawsze właściwe:
with open("notes.txt", encoding="utf-8") as f:
contents = f.read()
Przy starszych plikach ze środowisk opartych wyłącznie na Windowsie możesz też trafić na cp1252 albo latin-1. Złe zgadnięcie daje zniekształcone znaki albo UnicodeDecodeError.
pathlib: nowoczesna obsługa ścieżek
Moduł pathlib z biblioteki standardowej daje wygodniejsze API niż surowe napisy:
from pathlib import Path
path = Path("notes.txt")
# Prosty odczyt i zapis.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")
# Budowanie ścieżek bez martwienia się o / i \.
data_dir = Path("data")
log_path = data_dir / "today.log"
print(log_path)
print(log_path.exists())
print(log_path.suffix) # ".log"
print(log_path.stem) # "today"
print(log_path.parent) # "data"
Path.read_text() i write_text() to skróty dla wzorca with open(...) as f, gdy chcesz tylko odczytać albo zapisać wszystko naraz. Do iteracji linia po linii nadal używasz open albo path.open().
Mały przykład od początku do końca
Odczyt listy elementów z pliku, odfiltrowanie ich i zapis wyniku do innego pliku:
from pathlib import Path
source = Path("items.txt")
destination = Path("filtered.txt")
items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]
destination.write_text("\n".join(kept) + "\n")
print(f"Kept {len(kept)} items out of {len(items)}")
splitlines() to liniowy odpowiednik join. Dzieli tekst na znakach nowej linii i ich nie zachowuje, co jest wygodne, gdy i tak zamierzasz potem połączyć kawałki.
Gdy coś pójdzie nie tak
Otwarcie nieistniejącego pliku zgłasza FileNotFoundError. Próba odczytu pliku bez odpowiednich uprawnień zgłasza PermissionError. Oba są podklasami OSError, który z kolei jest podklasą Exception. O porządnej obsłudze wyjątków opowie następna strona.
Na razie krótka zapowiedź tego, jak wygląda obsługa błędów:
from pathlib import Path
path = Path("maybe.txt")
try:
contents = path.read_text()
except FileNotFoundError:
print("File doesn't exist - starting fresh.")
contents = ""
print(repr(contents))
Najważniejsze nawyki
- Zawsze używaj
with open(...)zamiast gołegoopeni ręcznego zamykania. - Przy plikach tekstowych zawsze przekazuj
encoding=, domyślnie UTF-8. - Duże pliki czytaj linia po linii, a nie w całości przez
.read(). - Do ścieżek i typowych wzorców odczytu i zapisu używaj
pathlib: oszczędzi ci to mnóstwa żonglowania napisami.
Najczęściej zadawane pytania
Jak odczytać plik w Pythonie?
Użyj open() z instrukcją with, która automatycznie zamyka plik, gdy skończysz. with open('file.txt') as f: contents = f.read() wczytuje cały plik do napisu. Aby czytać linia po linii, iteruj bezpośrednio po obiekcie pliku: for line in f:.
Czym różnią się tryby otwarcia 'r', 'w' i 'a'?
'r' to odczyt (domyślnie). 'w' to zapis: tworzy plik albo go czyści, jeśli istnieje. 'a' to dopisywanie: dodaje na końcu pliku, nie usuwając tego, co już w nim jest. Dodaj 'b' dla trybu binarnego albo '+' dla odczytu i zapisu.
Dlaczego używać with open zamiast samego open?
with open zamiast samego open?Instrukcja with gwarantuje, że plik zostanie zamknięty nawet wtedy, gdy w połowie wystąpi błąd. Bez with musisz samodzielnie wywołać .close() i pamiętać o tym na ścieżkach błędów. with jest bezpieczniejsze i wymaga mniej kodu.