14. Python – operacje na plikach


Szybki quiz – przypomnienie poprzedniej lekcji

Temat poprzedniej lekcji: operacje na ciągach znaków i wyrażenia regularne.

1. Co zostanie wyświetlone?

tekst = "Python"
print(tekst[1:4], tekst[-2:], tekst[::-1])
Odpowiedź

Odpowiedź: yth on nohtyP – [1:4] to znaki o indeksach 1, 2, 3; [-2:] to dwa ostatnie znaki; [::-1] odwraca napis.

2. Znajdź błąd w kodzie i popraw go.

imie = "ala"
imie[0] = "A"
Odpowiedź

Odpowiedź: TypeError – stringi są niemutowalne, nie można zmienić pojedynczego znaku. Poprawnie: imie = "A" + imie[1:] albo imie = imie.capitalize().

3. Co zostanie wyświetlone?

tekst = "kot"
tekst.replace("k", "m")
print(tekst)
Odpowiedź

Odpowiedź: kot – replace() nie zmienia oryginału, zwraca nowy string. Wynik trzeba przypisać: tekst = tekst.replace("k", "m").

4. Jaki będzie wynik działania programu?

tekst = "  Ala ma kota  "
print(tekst.strip().upper().split())
Odpowiedź

Odpowiedź: ['ALA', 'MA', 'KOTA'] – strip() usuwa spacje z brzegów, upper() zamienia na wielkie litery, split() dzieli po białych znakach i zwraca listę.

5. Czym różni się find() od index() przy szukaniu tekstu, którego nie ma w napisie?

Odpowiedź

Odpowiedź: find() zwraca -1, a index() zgłasza błąd ValueError.

6. Co należy uzupełnić w kodzie, aby liczba 5 została wyświetlona jako 005?

n = 5
print(f"{n:___}")
Odpowiedź

Odpowiedź: 03d (może być też 03) – wynik 005. Alternatywa bez f-stringa: str(n).zfill(3).

7. Co zwróci ten fragment kodu?

import re
print(re.findall(r"\d+", "Mam 3 koty i 12 psów"))
Odpowiedź

Odpowiedź: ['3', '12'] – \d+ to jedna lub więcej cyfr z rzędu, findall() zwraca listę wszystkich dopasowań.

8. Jak zamienić listę ["a", "b", "c"] na napis a, b, c?

Odpowiedź

Odpowiedź: ", ".join(["a", "b", "c"]) – join() wywołujemy na separatorze, a nie na liście.


Praca z plikami to fundamentalna umiejętność w programowaniu. Pozwala na:

  • Zapisywanie danych na stałe (przetrwają zamknięcie programu)
  • Wczytywanie danych z plików tekstowych, CSV, JSON
  • Tworzenie logów i raportów
  • Wymianę danych między programami

Podstawowe operacje:

  1. Otwieranie pliku
  2. Odczyt lub zapis danych
  3. Zamykanie pliku (automatyczne z with)

Ścieżki do plików

Ścieżka względna vs bezwzględna

Ścieżka względna – relatywna do bieżącego katalogu:

"plik.txt"
"dane/plik.txt"
"../plik.txt"

Ścieżka bezwzględna – pełna ścieżka od korzenia dysku:

# Windows
"C:/Users/Jan/Documents/plik.txt"

# Linux/Mac
"/home/jan/documents/plik.txt"

Moduł os – praca ze ścieżkami

import os

# Bieżący katalog (current working directory)
sciezka_biezaca = os.getcwd()
print(f"Obecny katalog: {sciezka_biezaca}")
# Np. C:\Users\Jan\Python\projekt

# Lista plików i katalogów w bieżącym katalogu
pliki = os.listdir()
print(f"Pliki w katalogu: {pliki}")

# Lista plików w konkretnym katalogu
pliki_dane = os.listdir("dane")
print(pliki_dane)

# Katalog nadrzędny (parent directory)
pliki_nadrzedne = os.listdir('..')
print(f"Pliki w katalogu nadrzędnym: {pliki_nadrzedne}")

Katalog domowy użytkownika

import os

# Katalog domowy
katalog_domowy = os.path.expanduser('~')
print(f"Katalog domowy: {katalog_domowy}")
# Windows: C:\Users\Jan
# Linux: /home/jan
# Mac: /Users/jan

Sprawdzanie istnienia pliku

import os

plik = "dane.txt"

# Czy plik istnieje?
if os.path.exists(plik):
    print(f"Plik {plik} istnieje")
else:
    print(f"Plik {plik} nie istnieje")

# Czy to plik?
if os.path.isfile(plik):
    print("To jest plik")

# Czy to katalog?
if os.path.isdir("dane"):
    print("To jest katalog")

Tryby otwierania plików

Przy otwieraniu pliku określamy tryb dostępu:

TrybNazwaOpis
'r'readOdczyt – plik musi istnieć
'w'writeZapis – tworzy nowy lub nadpisuje istniejący
'a'appendDopisywanie – na końcu pliku, tworzy jeśli nie istnieje
'x'exclusiveTworzenie – błąd jeśli plik istnieje
'r+'read/writeOdczyt i zapis – plik musi istnieć
'w+'write/readZapis i odczyt – nadpisuje
'a+'append/readDopisywanie i odczyt

Dodatkowe modyfikatory:

  • 't' – tryb tekstowy (domyślny)
  • 'b' – tryb binarny (dla obrazów, audio itp.)

Przykłady:

'r'   # Tylko odczyt, tekstowy
'rb'  # Tylko odczyt, binarny
'w'   # Tylko zapis, tekstowy
'wb'  # Tylko zapis, binarny
'a'   # Dopisywanie, tekstowy
'r+'  # Odczyt i zapis

Instrukcja with – bezpieczne otwieranie

Dlaczego with?

  • Automatycznie zamyka plik
  • Zwalnia zasoby

Składnia:

with open('plik.txt', 'r') as plik:
    # operacje na pliku
    zawartosc = plik.read()
    
# Tutaj plik jest już automatycznie zamknięty

Bez with (NIE ZALECANE)

# Stary sposób - musisz pamiętać o zamknięciu
plik = open('dane.txt', 'r')
zawartosc = plik.read()
plik.close()  # Łatwo zapomnieć!

# Problem: jeśli wystąpi błąd, plik może nie zostać zamknięty

Odczyt z pliku

read() – cała zawartość

# Odczyt całego pliku jako jeden string
with open('plik.txt', 'r', encoding='utf-8') as plik:
    zawartosc = plik.read()
    print(zawartosc)

Parametr encoding='utf-8' – ważny dla polskich znaków!

read(n) – n znaków

# Odczyt pierwszych 100 znaków
with open('plik.txt', 'r', encoding='utf-8') as plik:
    fragment = plik.read(100)
    print(fragment)

readline() – jedna linia

# Odczyt pojedynczej linii
with open('plik.txt', 'r', encoding='utf-8') as plik:
    pierwsza_linia = plik.readline()
    druga_linia = plik.readline()
    
    print(pierwsza_linia)
    print(druga_linia)

readlines() – lista linii

# Odczyt wszystkich linii jako lista
with open('plik.txt', 'r', encoding='utf-8') as plik:
    linie = plik.readlines()
    
    print(type(linie))  # <class 'list'>
    print(len(linie))   # Liczba linii
    
    # Iteracja po liniach
    for linia in linie:
        print(linia.rstrip())  # rstrip() usuwa \n na końcu

Iteracja bezpośrednia (NAJLEPSZE)

# Najbardziej efektywny sposób - bez wczytywania całości do pamięci
with open('plik.txt', 'r', encoding='utf-8') as plik:
    for linia in plik:
        print(linia.rstrip())

Zalety:

  • Oszczędza pamięć (nie wczytuje całego pliku)
  • Szybsze dla dużych plików
  • Prostsze

Przykład – wyszukiwanie w pliku

# Szukanie linii zawierającej konkretny tekst
with open('log.txt', 'r', encoding='utf-8') as plik:
    for numer, linia in enumerate(plik, 1):
        if 'ERROR' in linia:
            print(f"Linia {numer}: {linia.rstrip()}")

Zapis do pliku

write() – zapis stringa

UWAGA: Tryb 'w' nadpisuje cały plik!

# Zapis do nowego pliku (lub nadpisanie istniejącego)
with open('nowy.txt', 'w', encoding='utf-8') as plik:
    plik.write("To jest pierwsza linia\n")
    plik.write("To jest druga linia\n")

Ważne: write() NIE DODAJE automatycznie nowej linii – musisz sam dodać \n!

Zapis wielu linii

# Metoda 1: write() z \n
with open('dane.txt', 'w', encoding='utf-8') as plik:
    plik.write("Linia 1\n")
    plik.write("Linia 2\n")
    plik.write("Linia 3\n")

# Metoda 2: writelines() - lista stringów
linie = ["Linia 1\n", "Linia 2\n", "Linia 3\n"]
with open('dane.txt', 'w', encoding='utf-8') as plik:
    plik.writelines(linie)

Przykład – zapis listy

# Zapisywanie listy zakupów
zakupy = ["Mleko", "Chleb", "Masło", "Jajka"]

with open('zakupy.txt', 'w', encoding='utf-8') as plik:
    for produkt in zakupy:
        plik.write(produkt + "\n")

Dopisywanie do pliku (append)

Tryb 'a' dopisuje na końcu pliku, nie nadpisując go.

import datetime

# Dopisywanie z datą i czasem
with open('log.txt', 'a', encoding='utf-8') as plik:
    teraz = datetime.datetime.now()
    plik.write(f"Log z dnia {teraz}\n")

# Kolejne wywołanie dopisze kolejną linię
with open('log.txt', 'a', encoding='utf-8') as plik:
    plik.write("Nowy wpis w logu\n")

Przykład – dziennik

import datetime

def dodaj_wpis(tekst):
    """Dodaje wpis do dziennika z datą."""
    with open('dziennik.txt', 'a', encoding='utf-8') as plik:
        teraz = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        plik.write(f"[{teraz}] {tekst}\n")

# Użycie
dodaj_wpis("Program uruchomiony")
dodaj_wpis("Użytkownik zalogowany")
dodaj_wpis("Program zamknięty")

Wskaźnik pozycji w pliku

tell() – aktualna pozycja

with open('plik.txt', 'r', encoding='utf-8') as plik:
    print(f"Pozycja: {plik.tell()}")  # 0
    
    plik.read(10)
    print(f"Pozycja: {plik.tell()}")  # 10

seek() – przesunięcie wskaźnika

with open('plik.txt', 'r', encoding='utf-8') as plik:
    # Przesuń na początek
    plik.seek(0)
    
    # Odczyt
    dane1 = plik.read(20)
    
    # Wróć na początek
    plik.seek(0)
    
    # Odczyt od początku znowu
    dane2 = plik.read(20)

Przykład – wielokrotny odczyt

with open('plik.txt', 'r', encoding='utf-8') as plik:
    # Pierwszy odczyt
    zawartosc1 = plik.read()
    print(f"Pierwszy: {len(zawartosc1)} znaków")
    
    # Drugi odczyt (pusty - wskaźnik na końcu)
    zawartosc2 = plik.read()
    print(f"Drugi: {len(zawartosc2)} znaków")  # 0
    
    # Powrót na początek
    plik.seek(0)
    
    # Trzeci odczyt (działa)
    zawartosc3 = plik.read()
    print(f"Trzeci: {len(zawartosc3)} znaków")

Praca z wieloma plikami

Kopiowanie pliku

# Kopiowanie zawartości z jednego pliku do drugiego
with open('zrodlo.txt', 'r', encoding='utf-8') as zrodlo, \
     open('kopia.txt', 'w', encoding='utf-8') as cel:
    
    zawartosc = zrodlo.read()
    cel.write(zawartosc)

print("Plik skopiowany")

Łączenie plików

# Łączenie wielu plików w jeden
pliki_zrodlowe = ['plik1.txt', 'plik2.txt', 'plik3.txt']

with open('polaczony.txt', 'w', encoding='utf-8') as wyjscie:
    for nazwa_pliku in pliki_zrodlowe:
        with open(nazwa_pliku, 'r', encoding='utf-8') as wejscie:
            zawartosc = wejscie.read()
            wyjscie.write(zawartosc)
            wyjscie.write("\n" + "="*50 + "\n")  # Separator

print("Pliki połączone")

Przetwarzanie i zapisywanie

# Odczyt, przetworzenie, zapis
with open('dane.txt', 'r', encoding='utf-8') as wejscie, \
     open('przetworzone.txt', 'w', encoding='utf-8') as wyjscie:
    
    for linia in wejscie:
        # Przetwarzanie - wielkie litery
        przetworzona = linia.upper()
        wyjscie.write(przetworzona)

Obsługa błędów

try-except dla plików

try:
    with open('nieistniejacy.txt', 'r', encoding='utf-8') as plik:
        zawartosc = plik.read()
except FileNotFoundError:
    print("Błąd: Plik nie istnieje!")
except PermissionError:
    print("Błąd: Brak uprawnień do pliku!")
except Exception as e:
    print(f"Nieoczekiwany błąd: {e}")

Sprawdzanie przed otwarciem

import os

nazwa_pliku = 'dane.txt'

# Sprawdź czy istnieje
if os.path.exists(nazwa_pliku):
    with open(nazwa_pliku, 'r', encoding='utf-8') as plik:
        zawartosc = plik.read()
        print(zawartosc)
else:
    print(f"Plik {nazwa_pliku} nie istnieje")

Pliki binarne

Odczyt pliku binarnego

# Odczyt obrazu
with open('obrazek.jpg', 'rb') as plik:  # 'rb' - read binary
    dane_binarne = plik.read()
    print(f"Rozmiar: {len(dane_binarne)} bajtów")

Kopiowanie pliku binarnego

# Kopiowanie obrazu
with open('zdjecie.jpg', 'rb') as zrodlo, \
     open('kopia_zdjecia.jpg', 'wb') as cel:
    
    dane = zrodlo.read()
    cel.write(dane)

print("Obraz skopiowany")

Przykłady praktyczne

Przykład 1: System logowania

import datetime

def zapisz_log(wiadomosc, poziom="INFO"):
    """Zapisuje log z datą i poziomem."""
    with open('aplikacja.log', 'a', encoding='utf-8') as plik:
        teraz = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        plik.write(f"[{teraz}] [{poziom}] {wiadomosc}\n")

# Użycie
zapisz_log("Aplikacja uruchomiona")
zapisz_log("Użytkownik Jan zalogowany")
zapisz_log("Błąd połączenia z bazą danych", "ERROR")
zapisz_log("Aplikacja zamknięta")

Przykład 2: Książka adresowa

def dodaj_kontakt(imie, telefon):
    """Dodaje kontakt do pliku."""
    with open('kontakty.txt', 'a', encoding='utf-8') as plik:
        plik.write(f"{imie}|{telefon}\n")
    print(f"Kontakt {imie} dodany")

def wyswietl_kontakty():
    """Wyświetla wszystkie kontakty."""
    try:
        with open('kontakty.txt', 'r', encoding='utf-8') as plik:
            print("\n=== KONTAKTY ===")
            for linia in plik:
                imie, telefon = linia.strip().split('|')
                print(f"{imie}: {telefon}")
    except FileNotFoundError:
        print("Brak kontaktów")

def znajdz_kontakt(szukane_imie):
    """Znajduje kontakt po imieniu."""
    try:
        with open('kontakty.txt', 'r', encoding='utf-8') as plik:
            for linia in plik:
                imie, telefon = linia.strip().split('|')
                if imie.lower() == szukane_imie.lower():
                    print(f"Znaleziono: {imie} - {telefon}")
                    return
            print("Kontakt nie znaleziony")
    except FileNotFoundError:
        print("Brak pliku kontaktów")

# Użycie
dodaj_kontakt("Jan Kowalski", "123-456-789")
dodaj_kontakt("Anna Nowak", "987-654-321")
wyswietl_kontakty()
znajdz_kontakt("Jan Kowalski")

Przykład 3: Statystyki tekstu

def statystyki_pliku(nazwa_pliku):
    """Wyświetla statystyki pliku tekstowego."""
    try:
        with open(nazwa_pliku, 'r', encoding='utf-8') as plik:
            linie = plik.readlines()
            
            liczba_linii = len(linie)
            liczba_slow = 0
            liczba_znakow = 0
            
            for linia in linie:
                liczba_znakow += len(linia)
                liczba_slow += len(linia.split())
            
            print(f"=== STATYSTYKI: {nazwa_pliku} ===")
            print(f"Liczba linii: {liczba_linii}")
            print(f"Liczba słów: {liczba_slow}")
            print(f"Liczba znaków: {liczba_znakow}")
            print(f"Średnia długość linii: {liczba_znakow / liczba_linii:.2f}")
            
    except FileNotFoundError:
        print(f"Plik {nazwa_pliku} nie istnieje")

# Użycie
statystyki_pliku('tekst.txt')

Przykład 4: Filtrowanie pliku

def filtruj_plik(plik_wejsciowy, plik_wyjsciowy, slowo_kluczowe):
    """
    Kopiuje tylko linie zawierające słowo kluczowe.
    """
    licznik = 0
    
    with open(plik_wejsciowy, 'r', encoding='utf-8') as wejscie, \
         open(plik_wyjsciowy, 'w', encoding='utf-8') as wyjscie:
        
        for linia in wejscie:
            if slowo_kluczowe.lower() in linia.lower():
                wyjscie.write(linia)
                licznik += 1
    
    print(f"Skopiowano {licznik} linii zawierających '{slowo_kluczowe}'")

# Użycie
filtruj_plik('log.txt', 'bledy.txt', 'ERROR')

Przykład 5: Licznik wyrazów

from collections import Counter

def licznik_wyrazow(nazwa_pliku):
    """Zlicza wystąpienia każdego słowa w pliku."""
    try:
        with open(nazwa_pliku, 'r', encoding='utf-8') as plik:
            tekst = plik.read().lower()
            
            # Usuwanie znaków interpunkcyjnych (prosty sposób)
            import string
            for znak in string.punctuation:
                tekst = tekst.replace(znak, ' ')
            
            # Podział na słowa
            slowa = tekst.split()
            
            # Zliczanie
            licznik = Counter(slowa)
            
            # Wyświetlanie 10 najczęstszych
            print(f"\n10 najczęstszych słów w {nazwa_pliku}:")
            for slowo, liczba in licznik.most_common(10):
                print(f"{slowo}: {liczba}")
                
    except FileNotFoundError:
        print(f"Plik {nazwa_pliku} nie istnieje")

# Użycie
licznik_wyrazow('artykul.txt')

CSV – pliki z danymi tabelarycznymi

Zapis do CSV

import csv

# Dane do zapisania
dane = [
    ['Imię', 'Wiek', 'Miasto'],
    ['Jan', 25, 'Warszawa'],
    ['Anna', 30, 'Kraków'],
    ['Piotr', 28, 'Gdańsk']
]

# Zapis do CSV
with open('osoby.csv', 'w', newline='', encoding='utf-8') as plik:
    writer = csv.writer(plik)
    writer.writerows(dane)

print("Dane zapisane do CSV")

Odczyt z CSV

import csv

# Odczyt z CSV
with open('osoby.csv', 'r', encoding='utf-8') as plik:
    reader = csv.reader(plik)
    
    for wiersz in reader:
        print(wiersz)

Ćwiczenia – Operacje na plikach

Podstawy odczytu

  1. Stwórz plik test.txt z 3 liniami tekstu. Odczytaj i wyświetl całą zawartość.
  2. Odczytaj tylko pierwsze 50 znaków z pliku.
  3. Odczytaj pierwszą linię z pliku używając readline().
  4. Odczytaj wszystkie linie z pliku używając readlines() i wyświetl ich liczbę.
  5. Przejdź przez plik linijka po linijce używając pętli for.
  6. Odczytaj plik i policz ile jest w nim słów.
  7. Odczytaj plik i policz ile jest w nim znaków (z spacjami).
  8. Znajdź najdłuższą linię w pliku.
  9. Wyświetl tylko linie zawierające słowo „Python”.
  10. Policz ile razy w pliku występuje konkretne słowo.

Podstawy zapisu

  1. Stwórz nowy plik i zapisz w nim 3 linie tekstu.
  2. Zapisz listę 5 imion do pliku (każde w nowej linii).
  3. Zapisz liczby od 1 do 100 do pliku (każda w nowej linii).
  4. Stwórz plik i zapisz w nim tabliczkę mnożenia dla liczby 7.
  5. Pobierz od użytkownika 5 zdań i zapisz je do pliku.

Dopisywanie (append)

  1. Dopisz aktualna datę i czas do pliku logu.
  2. Stwórz funkcję która dopisuje wpis do dziennika z datą.
  3. Pobieraj od użytkownika notatki i dopisuj je do pliku dopóki nie wpisze „koniec”.
  4. Dopisz do istniejącego pliku listę nowych zadań.
  5. Stwórz prosty system TODO który dopisuje zadania do pliku.

Operacje na wielu plikach

  1. Skopiuj zawartość jednego pliku do drugiego.
  2. Połącz dwa pliki tekstowe w jeden.
  3. Odczytaj plik, zamień wszystkie litery na wielkie i zapisz do nowego pliku.
  4. Odczytaj plik, usuń puste linie i zapisz do nowego pliku.
  5. Odczytaj plik, ponumeruj linie i zapisz do nowego pliku.

Przetwarzanie danych

  1. Odczytaj plik z liczbami (każda w linii) i oblicz ich sumę.
  2. Odczytaj plik z liczbami i znajdź największą oraz najmniejszą.
  3. Odczytaj plik tekstowy i stwórz plik ze statystykami (liczba linii, słów, znaków).
  4. Odczytaj plik i zapisz tylko linie dłuższe niż 50 znaków do nowego pliku.
  5. Odczytaj plik i zapisz linie w odwrotnej kolejności do nowego pliku.

Filtrowanie i wyszukiwanie

  1. Znajdź i wyświetl wszystkie linie zawierające „@” (adresy email).
  2. Skopiuj do nowego pliku tylko linie zaczynające się od „#” (komentarze).
  3. Odczytaj plik logu i zapisz do nowego tylko linie zawierające „ERROR”.
  4. Znajdź wszystkie linie zawierające liczby i zapisz je osobno.
  5. Usuń z pliku wszystkie linie zawierające konkretne słowo.

Praca ze ścieżkami (moduł os)

  1. Wyświetl bieżący katalog roboczy.
  2. Wyświetl listę wszystkich plików w bieżącym katalogu.
  3. Sprawdź czy plik o podanej nazwie istnieje.
  4. Wyświetl listę wszystkich plików .txt w katalogu.
  5. Policz ile plików znajduje się w katalogu.

Obsługa błędów

  1. Spróbuj otworzyć nieistniejący plik i obsłuż błąd.
  2. Napisz funkcję która bezpiecznie odczytuje plik (obsługuje błędy).
  3. Sprawdź czy plik istnieje przed próbą otwarcia.
  4. Obsłuż błąd braku uprawnień do pliku.
  5. Napisz funkcję która próbuje otworzyć plik 3 razy przed poddaniem się.

Funkcje do pracy z plikami

  1. Napisz funkcję zapisz_liste(lista, nazwa_pliku) która zapisuje listę do pliku.
  2. Napisz funkcję wczytaj_liste(nazwa_pliku) która wczytuje listę z pliku.
  3. Napisz funkcję policz_linie(nazwa_pliku) która zwraca liczbę linii.
  4. Napisz funkcję znajdz_w_pliku(nazwa_pliku, szukane) która znajduje i zwraca linie zawierające szukany tekst.
  5. Napisz funkcję usun_duplikaty(plik_wejsciowy, plik_wyjsciowy) która usuwa powtarzające się linie.

CSV i dane strukturalne

  1. Zapisz listę słowników do pliku CSV (bez modułu csv).
  2. Odczytaj plik CSV i wyświetl dane w formacie tabelarycznym.
  3. Stwórz plik CSV z danymi uczniów (imię, nazwisko, klasa, średnia).
  4. Odczytaj plik CSV i znajdź ucznia z najwyższą średnią.
  5. Stwórz plik CSV z cenami produktów. Oblicz wartość całego magazynu.

JSON

  1. Zapisz słownik do pliku JSON.
  2. Odczytaj dane z pliku JSON.
  3. Zapisz listę słowników (dane użytkowników) do pliku JSON.
  4. Odczytaj JSON, zmodyfikuj dane i zapisz z powrotem.
  5. Stwórz bazę danych kontaktów w formacie JSON.

Pliki binarne

  1. Skopiuj plik binarny (np. obrazek).
  2. Sprawdź rozmiar pliku binarnego w bajtach.
  3. Odczytaj pierwsze 100 bajtów z pliku binarnego.
  4. Porównaj rozmiary pliku tekstowego i tego samego pliku skompresowanego.
  5. Napisz funkcję która sprawdza typ pliku na podstawie rozszerzenia.

Logowanie

  1. Stwórz prosty system logowania który zapisuje logi z datą i czasem.
  2. Napisz funkcję log(wiadomosc, poziom) która loguje z poziomami (INFO, WARNING, ERROR).
  3. Stwórz osobne pliki logów dla różnych poziomów.
  4. Ogranicz rozmiar pliku logu – jeśli przekroczy 1000 linii, zacznij nowy plik.
  5. Napisz funkcję która wyświetla ostatnie 10 linii z logu.

Kontakty/Książka adresowa

  1. Stwórz system dodawania kontaktów do pliku (imię, telefon, email).
  2. Napisz funkcję wyświetlającą wszystkie kontakty z pliku.
  3. Napisz funkcję wyszukującą kontakt po imieniu.
  4. Napisz funkcję usuwającą kontakt.
  5. Napisz funkcję edytującą kontakt.

TODO list

  1. Stwórz prosty system TODO z zapisem do pliku.
  2. Dodaj możliwość oznaczania zadań jako wykonane.
  3. Dodaj priorytet zadań (niski, średni, wysoki).
  4. Wyświetl tylko zadania nieukończone.
  5. Posortuj zadania według priorytetu.

Statystyki i analizy

  1. Napisz funkcję analizującą plik tekstowy (najczęstsze słowo, najdłuższe słowo, średnia długość słowa).
  2. Policz wystąpienia każdej litery w pliku.
  3. Stwórz histogram długości słów w pliku.
  4. Znajdź wszystkie unikalne słowa w pliku.
  5. Policz ile razy każde słowo występuje w pliku (użyj Counter).

Backup i archiwizacja

  1. Napisz funkcję tworzącą kopię zapasową pliku (dopisz datę do nazwy).
  2. Stwórz funkcję która zapisuje historię zmian w pliku.
  3. Napisz funkcję która przywraca plik z backupu.
  4. Stwórz rotację backupów – zachowaj tylko 5 najnowszych.
  5. Napisz funkcję porównującą dwa pliki i wyświetlającą różnice.

Konfiguracja

  1. Stwórz plik konfiguracyjny (nazwa=wartość w każdej linii) i funkcje do odczytu.
  2. Napisz funkcję zapisującą ustawienia do pliku konfiguracyjnego.
  3. Stwórz domyślną konfigurację jeśli plik nie istnieje.
  4. Waliduj konfigurację podczas wczytywania.
  5. Dodaj komentarze do pliku konfiguracyjnego (linie zaczynające się od #).

Raportowanie

  1. Napisz funkcję generującą raport HTML z danymi z pliku.
  2. Stwórz raport zawierający statystyki z wielu plików.
  3. Wygeneruj raport CSV z podsumowaniem danych.
  4. Stwórz raport tekstowy z formatowaniem (ramki, wyrównanie).
  5. Napisz funkcję która generuje raport porównawczy z dwóch plików.

Zadania kompleksowe

  1. Stwórz prosty system zarządzania uczniami: dodawanie, usuwanie, edycja, wyświetlanie, zapisywanie do pliku.
  2. Napisz program do analizy logów serwera: zlicz błędy, ostrzeżenia, wyświetl statystyki.
  3. Stwórz system inwentaryzacji: produkty z ilościami, cenami, raport wartości magazynu.
  4. Napisz program do zarządzania wydatkami: dodawanie wydatków, kategorie, raporty miesięczne, zapis do pliku.
  5. Stwórz system rezerwacji: terminy, zarezerwowane/wolne, zapis do pliku, walidacja.
  6. Napisz grę tekstową która zapisuje stan gry do pliku i pozwala wczytać zapisany stan.
  7. Stwórz prosty system blogowy: posty z datą, tytułem, treścią, zapisywanie do plików.
  8. Napisz konwerter między formatami (TXT ↔ CSV ↔ JSON).
  9. Stwórz system punktacji quizu z zapisem wyników do pliku i rankingiem.
  10. Napisz program szyfrujący i deszyfrujący pliki tekstowe (np. szyfr Cezara).

PODSUMOWANIE

Co uczeń musi rozumieć w tym temacie:

  • Plik to trwałe miejsce zapisu danych – po zamknięciu programu dane zostają. Praca z plikiem to zawsze: otwórz → odczytaj/zapisz → zamknij.
  • Plik otwieramy przez with open(...) as plik:. Blok with gwarantuje zamknięcie pliku, także gdy w środku wystąpi błąd. Nie zastępuje jednak try/except – błędu, np. braku pliku, nadal trzeba obsłużyć osobno.
  • Tryb otwarcia decyduje o tym, co się stanie z plikiem:
    • 'r' – odczyt, plik musi istnieć,
    • 'w' – zapis, kasuje dotychczasową zawartość (albo tworzy plik),
    • 'a' – dopisywanie na końcu,
    • 'x' – utworzenie nowego pliku, błąd jeśli już istnieje.
  • write() zapisuje dokładnie to, co dostanie, i nie dodaje \n. Podział na linie to sprawa programisty. write() przyjmuje tylko str – liczby trzeba zamienić przez str() lub f-string.
  • Odczyt zwraca tekst: read() – całość, readline() – jedną linię, readlines() – listę linii. Linie z pliku zawierają \n na końcu – dlatego używamy rstrip() lub strip().
  • Najlepszy sposób czytania linia po linii to pętla for linia in plik: (nie wczytuje całego pliku do pamięci).
  • Plik ma wskaźnik pozycji. Po odczycie całości wskaźnik jest na końcu i kolejne read() zwraca ''. Powrót na początek: seek(0).
  • Polskie znaki wymagają encoding='utf-8' w open(). Bez niego odczyt może dać błąd lub „krzaczki” (zależy od systemu).
  • Dla plików binarnych (obrazy, audio) używamy trybów z b ('rb', 'wb') – dane są wtedy bajtami, a nie tekstem. Parametru encoding w trybie binarnym nie podajemy.
  • Typowe błędy wykonania przy plikach: FileNotFoundError (brak pliku), PermissionError (brak uprawnień), FileExistsError (tryb 'x').
  • Moduł os pozwala sprawdzić środowisko przed otwarciem pliku: os.getcwd(), os.listdir(), os.path.exists(), os.path.isfile(), os.path.isdir().
  • Dane tabelaryczne zapisujemy i czytamy modułem csv (csv.writer, csv.reader). Przy zapisie dodajemy newline=''.

Najczęstsze źródła błędów:

  • użycie 'w' zamiast 'a' i utrata starych danych,
  • brak \n w write() – wszystko ląduje w jednej linii,
  • write() z liczbą zamiast napisu,
  • próba odczytu po wyjściu z bloku with (plik jest już zamknięty),
  • ponowny read() bez seek(0) – pusty wynik,
  • zapomniane rstrip() – puste linie w wydruku, bo print() też dodaje \n,
  • zła ścieżka lub zły katalog roboczy (plik istnieje, ale nie w miejscu, gdzie szuka go program),
  • brak encoding='utf-8'.

Minimum, które powinno wejść w pamięć

Jeżeli masz zapamiętać tylko kilka rzeczy z tej lekcji, zapamiętaj te:

  1. Plik zawsze otwieraj tak: with open('plik.txt', 'r', encoding='utf-8') as plik:
  2. Tryby: r odczyt, w zapis (kasuje stare dane!), a dopisywanie, x tylko nowy plik.
  3. write() nie dodaje \n – dodaj go sam i zapisuj tylko napisy (str).
  4. Linie z pliku mają \n na końcu – usuń go przez rstrip() / strip().
  5. Czytanie linia po linii: for linia in plik:
  6. Po przeczytaniu całego pliku wskaźnik jest na końcu – wróć na początek przez seek(0).
  7. Brak pliku to FileNotFoundError – obsłuż go przez try/except.
  8. Zanim użyjesz pliku, możesz sprawdzić os.path.exists(nazwa).
  9. Dane w jednej linii rozdzielone znakiem (np. Jan|123) czytasz przez strip().split('|') – to połączenie tej lekcji z poprzednią.
  10. Obrazy i inne pliki nietekstowe: tryby 'rb' i 'wb'.

Ściągawka – najważniejsze polecenia i składnia

Otwieranie pliku

with open('plik.txt', 'r', encoding='utf-8') as plik:
    ...   # tutaj plik jest otwarty; po wyjściu z bloku – zamknięty

Tryby

TrybZnaczenieGdy brak plikuGdy plik istnieje
'r'odczytFileNotFoundErrorczyta
'w'zapistworzykasuje zawartość
'a'dopisywanietworzydopisuje na końcu
'x'tworzenietworzyFileExistsError
'r+'odczyt i zapisFileNotFoundErrorczyta i zapisuje
'rb', 'wb'binarniejak 'r', 'w'jak 'r', 'w'

Odczyt

InstrukcjaZwraca
plik.read()cały plik jako jeden string
plik.read(n)n znaków
plik.readline()jedną linię (z \n)
plik.readlines()listę linii (z \n)
for linia in plik:kolejne linie, bez wczytywania całości

Zapis

plik.write("tekst\n")             # jeden napis, \n dodajemy sami
plik.writelines(["a\n", "b\n"])   # lista napisów, każdy z \n
plik.write(str(liczba) + "\n")    # liczbę najpierw na string

Wskaźnik pozycji

plik.tell()    # aktualna pozycja
plik.seek(0)   # skok na początek

Dwa pliki naraz

with open('we.txt', 'r', encoding='utf-8') as we, \
     open('wy.txt', 'w', encoding='utf-8') as wy:
    for linia in we:
        wy.write(linia.upper())

Obsługa błędów

try:
    with open('dane.txt', 'r', encoding='utf-8') as plik:
        ...
except FileNotFoundError:
    print("Plik nie istnieje")
except PermissionError:
    print("Brak uprawnień")

Moduł os

import os
os.getcwd()               # bieżący katalog
os.listdir()              # lista plików i katalogów
os.path.exists('x.txt')   # czy istnieje (plik lub katalog)
os.path.isfile('x.txt')   # czy to plik
os.path.isdir('dane')     # czy to katalog

CSV

import csv
with open('osoby.csv', 'w', newline='', encoding='utf-8') as plik:
    csv.writer(plik).writerows(dane)      # dane = lista list

with open('osoby.csv', 'r', encoding='utf-8') as plik:
    for wiersz in csv.reader(plik):       # wiersz = lista
        print(wiersz)

Wzorzec: dopisywanie wpisu z datą

import datetime
with open('log.txt', 'a', encoding='utf-8') as plik:
    teraz = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    plik.write(f"[{teraz}] {tekst}\n")

Quiz – sprawdź się

1. (Teoria) Przypisz do każdego opisu tryb: 'r', 'w', 'a', 'x'.

  • a) Dopisuje dane na końcu pliku, a gdy pliku nie ma – tworzy go.
  • b) Zgłasza błąd, jeśli plik już istnieje.
  • c) Kasuje dotychczasową zawartość pliku.
  • d) Wymaga, aby plik istniał.

2. (Teoria) Podaj dwie korzyści używania with open(...) zamiast open() i close().

3. (Co zostanie zapisane?) Jaka będzie zawartość pliku a.txt po uruchomieniu kodu? Ile będzie w nim linii?

with open("a.txt", "w", encoding="utf-8") as p:
    p.write("Ala")
    p.write("Ola\n")
    p.write("Ela")

4. (Co zostanie wyświetlone?) Plik dane.txt zawiera trzy linie: Ala, Ma, Kota.

with open("dane.txt", "r", encoding="utf-8") as p:
    p.readline()
    print(p.read().split())

5. (Znajdź błąd) Program ma zapisać do pliku liczbę punktów. Dlaczego się nie uruchomi i jak go poprawić?

punkty = 100
with open("wyniki.txt", "w", encoding="utf-8") as p:
    p.write(punkty)

6. (Znajdź błąd) Co się stanie po uruchomieniu i dlaczego?

with open("dane.txt", "r", encoding="utf-8") as p:
    pierwsza = p.readline()
druga = p.readline()

7. (Uzupełnij kod) Dopisz do pliku log.txt nową linię o treści Start, nie kasując poprzednich wpisów. Co wstawić w miejsca ___?

with open("log.txt", "___", encoding="utf-8") as p:
    p.write("Start___")

8. (Przewidywanie działania) Plik litery.txt zawiera jedną linię: abcdef. Co zostanie wyświetlone?

with open("litery.txt", "r", encoding="utf-8") as p:
    a = p.read(2)
    b = p.read(2)
    p.seek(0)
    c = p.read(3)
print(a, b, c)

9. (Dlaczego tak działa?) Po wypisaniu zawartości pliku pętlą między liniami pojawiają się puste wiersze. Dlaczego? Jak to naprawić?

with open("lista.txt", "r", encoding="utf-8") as p:
    for linia in p:
        print(linia)

10. (Co zostanie wyświetlone?) Plik brak.txt nie istnieje.

try:
    with open("brak.txt", "r", encoding="utf-8") as p:
        print(p.read())
except FileNotFoundError:
    print("Brak pliku")
print("Koniec")

11. (Połączenie z poprzednią lekcją) Linia z pliku kontakty.txt ma postać "Jan|123\n". Co zwróci wyrażenie "Jan|123\n".strip().split("|")? Jak użyć go do przypisania imienia i telefonu do dwóch zmiennych?

12. (Wybór poprawnej składni) Która wersja poprawnie otwiera plik CSV do zapisu?

  • A) open('osoby.csv', 'r', newline='', encoding='utf-8')
  • B) open('osoby.csv', 'w', newline='', encoding='utf-8')
  • C) open('osoby.csv', 'a+b', encoding='utf-8')

13. (Zadanie praktyczne) Napisz program, który zapisuje do pliku liczby.txt liczby od 1 do 5, każdą w osobnej linii.

14. (Zadanie praktyczne) Napisz funkcję suma_z_pliku(nazwa_pliku), która odczytuje plik z liczbami całkowitymi (jedna w linii) i zwraca ich sumę. Jeśli pliku nie ma, funkcja ma wypisać komunikat i zwrócić 0.

Odpowiedzi

1. a) 'a', b) 'x', c) 'w', d) 'r'.

2. Np.: plik jest zamykany automatycznie, także wtedy, gdy w bloku wystąpi błąd; nie trzeba pamiętać o close(); kod jest krótszy i czytelniejszy.

3. Zawartość: AlaOla w pierwszej linii i Ela w drugiej (AlaOla\nEla). Są 2 linie – pierwszy write() nie ma \n, więc „Ala” i „Ola” są połączone.

4. ['Ma', 'Kota'] – readline() pobiera i pomija pierwszą linię, read() zwraca resztę, split() dzieli ją na słowa.

5. TypeError – write() przyjmuje tylko napis. Poprawnie: p.write(str(punkty) + "\n") albo p.write(f"{punkty}\n").

6. ValueError (operacja na zamkniętym pliku). Po wyjściu z bloku with plik jest zamknięty – drugi readline() trzeba wykonać wewnątrz bloku (z wcięciem).

7. Tryb "a" oraz \n: open("log.txt", "a", ...) i p.write("Start\n").

8. ab cd abc – dwa odczyty po 2 znaki dają ab i cd, seek(0) wraca na początek, więc trzeci odczyt daje abc.

9. Każda linia z pliku kończy się znakiem \n, a print() dodaje kolejny – stąd puste wiersze. Poprawka: print(linia.rstrip()) (lub strip()).

10. Wyświetli się:

Brak pliku
Koniec

Błąd został obsłużony, więc program nie przerywa działania i wykonuje ostatnią linię.

11. Wynik: ['Jan', '123']. Przypisanie: imie, telefon = "Jan|123\n".strip().split("|"). Gdyby nie strip(), telefon zawierałby \n na końcu.

12. B – tryb 'w' służy do zapisu; A otwiera plik tylko do odczytu, a C to tryb binarny, nieodpowiedni dla pliku CSV.

13. Przykładowe rozwiązanie:

with open("liczby.txt", "w", encoding="utf-8") as plik:
    for i in range(1, 6):
        plik.write(f"{i}\n")

14. Przykładowe rozwiązanie:

def suma_z_pliku(nazwa_pliku):
    suma = 0
    try:
        with open(nazwa_pliku, "r", encoding="utf-8") as plik:
            for linia in plik:
                suma += int(linia.strip())
    except FileNotFoundError:
        print(f"Plik {nazwa_pliku} nie istnieje")
        return 0
    return suma