PY_I_R_W13A_M07 Obsługa plików tekstowych
Podstawowe operacje na plikach w języku Python to:
zapis danych tekstowych ASCII do pliku,
odczyt danych tekstowych ASCII z pliku,
zapis danych binarnych do pliku,
odczyt danych binarnych z pliku.
W systemie operacyjnym plik składa się z kolejnych bajtów informacji. Zawsze ma swoją nazwę i jest umiejscowiony w katalogu. W zależności od systemu plików dane te mogą mieć różne ograniczenia. Oto kilka przykładów:
system plików | ograniczenia |
|---|---|
| długość nazwy pliku nie może przekraczać 8 znaków |
| bezwzględna ścieżka pliku; maksymalna długość pełnej ścieżki dostępu nie może przekraczać 260 znaków |
| bezwzględna ścieżka pliku; maksymalna długość pełnej ścieżki dostępu nie może przekraczać 4096 znaków |
Istnieje też różnica w zapisie separatora katalogów:
system operacyjny | separator katalogów |
|---|---|
DOS, Windows |
|
Linux, UNIX, MacOS |
|
Dodatkowo, w systemach istnieją także różnice w definiowaniu dysków/partycji:
system operacyjny | oznaczenie partycji |
|---|---|
DOS, Windows | oznaczenie literowe, np. |
dystrybucje systemu Linux, UNIX, MacOS | To bardziej skomplikowane zagadnienie, więcej informacji znajdziesz w e‑materiałach poświęconych temu zagadnieniu. |
W programach, które mają być wieloplatformowe, zawsze należy zapisać odpowiednio ścieżki dostępu do plików. W tym celu możemy stosować metodę path() z modułu os.
W tym e‑materiale będziemy używać plików znajdujących się w tym samy katalogu co program. Dzięki temu unikniemy problemów związanych ze sposobem zapisu ścieżki dostępu w różnych systemach operacyjnych.
Jeśli chcemy wykonywać operacje odczytu/zapisu pliku na dysku, używamy specjalnej konstrukcji w języku Python:
Dzięki takiemu zapisowi nie musimy dbać o zamykanie pliku po operacjach odczytu/zapisu oraz uzyskujemy obiekt plik i wszystkie metody niezbędne do operacji na plikach:
Zapisywanie i odczytywanie danych tekstowych do i z pliku
Zdefiniujmy funkcję zapisującą (o nazwie funkcja_zapisujaca())dane podane jako parametr do pliku tekstowego, którego nazwa będzie kolejnym parametrem. Jeśli nie podamy nazwy, funkcja przyjmie domyślną wartość plik_tekstowy.txt.
W kodzie używamy drugiego parametru w metodzie open() (linia 2 open(plik, "w")). Opisujemy go w dalszej części e‑materiału.
Funkcja utworzy plik, jeśli jeszcze nie istniał, i zapisze do niego linię tekstu. Jeżeli plik istniał, zostanie nadpisany. Metoda write() zwróci 42 – liczbę znaków zapisanych do pliku, a tym samym rozmiar pliku – 42 bajty.
Oto wynik działania polecenia stat w dystrybucji systemu Linux o nazwie Ubuntu (rozmiar 44 bajty wynika z użycia 2 znaków z rozszerzonego ASCII, czyli UTF‑8 (ó oraz ę), a więc 2 znaki po 2 bajty + 40 znaków po 1 bajt):
Właściwości takiego pliku wyglądają następująco:

Funkcja open() ma dwa parametry:
nazwę pliku, do którego ma nastąpić zapis lub z którego będzie następował odczyt,
tryb dostępu do pliku.
tryb | opis działania |
|---|---|
| tryb czytania (domyślny) |
| tryb zapisu, nadpisuje poprzedni plik, jeśli istniał |
| tryb zapisu, dopisuje na końcu pliku lub zapisuje w nowym, jeżeli plik nie istniał |
| tryb binarny |
| tryb tekstowy ASCII (domyślny) |
W języku Python możemy odczytywać dane z plików, np. z plików tekstowych, za pomocą metod powiązanych z obiektem plikowym utworzonym poprzez składnię with open(...) as plik:
metoda | opis |
|---|---|
| czyta określoną przez |
| czyta jedną, kolejną linię z pliku; zwraca obiekt typu |
| czyta cały plik, umieszczając kolejne linie jako elementy listy; zwraca obiekt typu |
Sprawdźmy, jak będą działały te metody dla przykładowego pliku o nazwie plik_testowy.txt i zawartości:
Przykład odczytania całego pliku przez metodę read():
Przykład odczytania pliku do kilku obiektów przez metodę readline():
Każda zmienna odczytuje jedną linię wraz ze znakami końca linii. W ten sam sposób wyświetli to program.
Przykład odczytania pliku do obiektu przez metodę readlines():
Napisz program, który
zapisze w pliku tekstowym zdanie: „Pierwszy wiersz tekstu”;
otworzy zapisany plik i dopisze do niego zdanie: „Drugi wiersz dopisany”;
otworzy zapisany plik i wypisze jego zawartość.
Metoda readlines() odczytuje wszystkie wiersze z pliku i zwraca je zapisane w liście. Trzeba pamiętać, że wiersze zakończone będą znakami nowego wiersza. Możliwe znaki to:
znak
"\n", czyli LF (ang. line feed),znaki
"\r\n", czyli CRLF (CR, ang. carriage return).
Jeżeli plik otwieramy tak jak w podanych wcześniej przykładach, np. open(nazwa_pliku, tryb), na końcu wierszy umieszczony zostanie znak "\n" niezależnie od znaków końca wiersza w pliku. Jeżeli jednak plik otworzymy, podając dodatkowy argument newline="", np. open(nazwa_pliku, tryb, newline=""), znaki końca wiersza będą takie, jak w pliku tekstowym.
Podczas wypisywania wierszy zawierających znak LF lub CRLF dodawany jest pusty wiersz. Usunięcie znaków nowego wiersza z ciągu znakowego jest możliwe na kilka sposobów, np.:
"wiersz\n".strip(),"wiersz\n".replace("\n", ""),"wiersz\n".replace("\r\n", "").
Format JSON
Język Python umożliwia również łatwą obsługę plików tekstowych zapisanych w formacie JSON, który pozwala wymieniać dane pomiędzy różnymi językami programowania. Format ten umożliwia między innymi zapisywanie w plikach tekstowych i późniejszy odczyt złożonych struktur danych, takich jak np. listy czy słowniki. Korzystanie z formatu wymaga zaimportowania modułu json. Najważniejsze funkcje to:
funkcja | opis |
|---|---|
| zapisuje obiekt |
| odczytuje dane z pliku |
Zdefiniujemy funkcje pozwalające na zapisanie w pliku tekstowym listy liczb zapisanych w słowniku oraz późniejsze odczytanie tych danych.
Nazwy plików przechowujących dane w formacie JSON mogą, chociaż nie jest to wymagane, mieć rozszerzenie .json. Do zapisu danych w formacie JSON wykorzystujemy metodę dump() zdefiniowaną w module json, który należy zaimportować na początku programu. Metoda wymaga podania danych do zapisania (np. w postaci słownika lub listy) oraz obiektu pliku otwartego do zapisu przez funkcję open().
Odczytywanie danych polega na użyciu metody load(), która wymaga jedynie obiektu pliku otwartego do odczytu przez funkcję open(). Zwracane dane zachowują swoją strukturę, tzn. odtwarzany zostaje ich typ, np. słownik czy lista.
Pliki w formacie JSON można edytować w edytorach tekstu.
Przykładowy program
Obsługa dziennika szkolnego
Program najpierw poprosi użytkownika o podanie nazwy klasy, do której należeć ma dziennik. Następnie użytkownik dodaje informacje na temat uczniów (opcja nr 1). Jeśli użytkownik spróbuje wczytać oceny osoby (opcja nr 2), nim ta zostanie dodana, program poinformuje go, że uczeń nie istnieje i wróci do menu. Po dodaniu ocen dziennik można zapisać (opcja nr 3). Jeśli zapisaliśmy wcześniej inny dziennik, możemy wczytać go w dowolnym momencie opcją nr 4.
Gdy program prosi cię o podjęcie decyzji za pomocą wybrania opcji t (skrót od tak) lub n (skrót od nie), tylko wybór t (małej litery) zatwierdzi działanie. Wszystkie inne wprowadzone znaki (również dużą literę T) program zinterpretuje jak n.
Poniższy program należy uruchomić, korzystając z wersji języka Python 3.10 lub wyższej, ponieważ wykorzystany w nim został operator | – wykonuje operację dodawania kluczy i wartości ze słownika.
Rozbuduj program tak, by działanie można było zatwierdzić wprowadzeniem dużej litery T oraz małej litery t, natomiast odrzucić je wprowadzeniem dużej litery N oraz małej litery n. Po wprowadzeniu innego znaku program powinien prosić użytkownika o wprowadzenie poprawnej odpowiedzi. Dodatkowo zabezpiecz program przed błędnymi danymi (np. oceną spoza zakresu).
W programie użyto słownika KLASA jako głównej struktury danych przechowującej informacje o klasie, między innymi nazwę klasy oraz dane uczniów. Dane te również zapisywane są w słownikach i obejmują numer ucznia pełniący rolę identyfikatora, imię i nazwisko oraz oceny z przedmiotów. Te ostatnie zapisywane są w listach. Przedmioty, z których można wpisywać oceny, zapisane zostały w liście PRZEDMIOTY.
Program wyposażono w możliwość odczytywania i zapisywania danych.
Zapisywanie danych
Informacje o klasie zapisywane są w pliku o przykładowej nazwie edziennik_1A.txt, gdzie 1A to nazwa klasy. Dane do zapisu w postaci ciągu znaków przygotowywane są przez funkcję zapisz_dziennik(). Zawierają one numery oraz imiona i nazwiska uczniów oddzielone znakiem dwukropka w osobnych wierszach, np.:
Do zapisania przygotowanych danych w pliku tekstowym wykorzystywana jest funkcja zapisz_plik_txt() wymagająca dwóch argumentów: nazwy pliku oraz danych w postaci ciągu znaków. Funkcja ta ilustruje użycie metody write().
W funkcji zapisz_dziennik() dla każdego ucznia, którego dane i oceny dodano do słownika KLASA, wywoływana jest funkcja zapisz_oceny() otrzymująca jako argument numer ucznia. Funkcja ta przygotowuje do zapisu oceny ucznia w postaci słownika, np.:
Oceny uczniów zapisywane są do plików tekstowych w formacie JSON o przykładowej nazwie 1A_1_Adam_Woźniak.json, gdzie 1A to nazwa klasy, a 1 to numer ucznia. Zadanie to realizuje funkcja zapisz_plik_json() przy użyciu metody dump() z modułu json.
Odczytywanie danych
Po uruchomieniu programu lub później po wybraniu polecenia Wczytaj dziennik wywoływana jest funkcja wczytaj_dziennik(), która pobiera nazwę klasy. Jeżeli ją podamy, wywołana zostanie funkcja wczytaj_plik_txt() – jej zadaniem jest odczytanie całej zawartości pliku przy użyciu metody readlines().
Zwrócona zawartość przetwarzana jest dalej w pętli for wiersz po wierszu. Instrukcja nr, nazwisko = wiersz.strip().split(':') usuwa z wierszy znak końca wiersza, rozbija wiersz (używając znaku dwukropka jako separatora) na dwuelementową listę i wreszcie odczytuje z niej numer oraz imię i nazwisko ucznia. Dalej tworzony jest słownik z danymi ucznia i wywoływana jest funkcja wczytaj_oceny(), która jako argument otrzymuje numer ucznia.
Odczytywanie ocen realizuje funkcja wczytaj_plik_json() wykorzystując metodę load() z modułu json do wczytania danych z podanego jako argument pliku. Dane zwrócone do funkcji wczytaj_oceny() zostają zapisane w słowniku oceny, który w instrukcji KLASA[nr] = KLASA[nr] | oceny jest dołączany do słownika KLASA.
W funkcjach odczytujących: wczytaj_plik_txt() i wczytaj_plik_json() – zastosowano konstrukcję try ... except ..., aby przechwycić i obsłużyć wyjątek FileNotFoundError, który generowany jest w przypadku braku podanego pliku na dysku.
Zapisywanie i odczytywanie danych binarnych do i z pliku
Python udostępnia też moduł o nazwie pickle, który służy do zapisu danych binarnych. Jest to zapis specyficzny dla języka Python i nie jest kompatybilny z innymi językami programowania. Najważniejsze funkcje tego modułu to:
funkcja | opis |
|---|---|
| zapisuje obiekt |
| odczytuje dane z pliku |
Sprawdźmy, jak możemy zapisywać dane w postaci binarnej, nie tylko sam tekst. Zdefiniujmy obiekt typu list i zapiszmy go do pliku plik_danych.bin.
Plik plik_danych.bin nie jest zwykłym plikiem tekstowym. Do jego utworzenia używamy opcji 'wb' funkcji open(), która oznacza zapis pliku w formacie binarnym. Jego zawartość możemy zobaczyć w specjalnym edytorze do plików binarnych.

Odczytanie danych z takiego pliku pozwala zobaczyć wartości w postaci obiektu w języku Python.
Napisz program, który do listy dane doda dwa ciągi znakowe: „Pierwsze zdanie” oraz „Drugie zdanie”. Następnie program powinien zapisać listę w pliku przy użyciu modułu pickle. Na końcu odczytaj zawartość pliku do obiektu o wybranej nazwie, wypisz zawartość obiektu oraz jego typ.
Podsumujmy najważniejsze wiadomości:
Python daje kilka możliwości zapisu i odczytu danych.
Dane można zapisywać do plików tekstowych w trybie nadpisywania lub dopisywania.
Python zawiera wbudowany moduł
pickleprzeznaczony do binarnego zapisywania i odczytywania obiektów tego języka.
Słownik
(ang. American Standard Code for Information Interchange) system kodowania znaków oparty na 7 bitach, zawiera kody liczbowe od 0 do 127 przyporządkowane m.in. znakom specjalnym, literom alfabetu łacińskiego, cyfrom czy znakom przestankowym; rozszerzany później przez systemy 8‑bitowe, np. ISO 8859‑2, Windows‑1250, współcześnie zastąpiony standardem UTF‑8
dane, które są fizyczną reprezentacją różnych obiektów, np. zdjęć czy muzyki; oglądane bezpośrednio przez człowieka nie pokazują realnej zawartości
ang. JavaScript Object Notation, tekstowy format wymiany danych obsługiwany przez wiele języków, pozwala między innymi na zapisywanie złożonych struktur danych takich jak listy czy słowniki w plikach tekstowych
zgodny, taki, który może być stosowany w różnych środowiskach
polecenie w systemach Linux, które wyświetla dokładne informacje na temat pliku lub systemu plików, takie jak np. rozmiar, typ pliku, prawa dostępu, czas ostatniego dostępu, modyfikacji, zmiany i utworzenia.
sposób organizacji zapisu plików na dysku komputera w systemie operacyjnym
dokładna lokalizacja pliku w strukturze katalogów wraz z nazwą, np: C:\Users\Python\Plik.txt lub /home/python/plik.txt.