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:
- Otwieranie pliku
- Odczyt lub zapis danych
- 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:
| Tryb | Nazwa | Opis |
|---|---|---|
'r' | read | Odczyt – plik musi istnieć |
'w' | write | Zapis – tworzy nowy lub nadpisuje istniejący |
'a' | append | Dopisywanie – na końcu pliku, tworzy jeśli nie istnieje |
'x' | exclusive | Tworzenie – błąd jeśli plik istnieje |
'r+' | read/write | Odczyt i zapis – plik musi istnieć |
'w+' | write/read | Zapis i odczyt – nadpisuje |
'a+' | append/read | Dopisywanie 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
- Obsługuje błędy
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
- Stwórz plik
test.txtz 3 liniami tekstu. Odczytaj i wyświetl całą zawartość. - Odczytaj tylko pierwsze 50 znaków z pliku.
- Odczytaj pierwszą linię z pliku używając
readline(). - Odczytaj wszystkie linie z pliku używając
readlines()i wyświetl ich liczbę. - Przejdź przez plik linijka po linijce używając pętli
for. - Odczytaj plik i policz ile jest w nim słów.
- Odczytaj plik i policz ile jest w nim znaków (z spacjami).
- Znajdź najdłuższą linię w pliku.
- Wyświetl tylko linie zawierające słowo „Python”.
- Policz ile razy w pliku występuje konkretne słowo.
Podstawy zapisu
- Stwórz nowy plik i zapisz w nim 3 linie tekstu.
- Zapisz listę 5 imion do pliku (każde w nowej linii).
- Zapisz liczby od 1 do 100 do pliku (każda w nowej linii).
- Stwórz plik i zapisz w nim tabliczkę mnożenia dla liczby 7.
- Pobierz od użytkownika 5 zdań i zapisz je do pliku.
Dopisywanie (append)
- Dopisz aktualna datę i czas do pliku logu.
- Stwórz funkcję która dopisuje wpis do dziennika z datą.
- Pobieraj od użytkownika notatki i dopisuj je do pliku dopóki nie wpisze „koniec”.
- Dopisz do istniejącego pliku listę nowych zadań.
- Stwórz prosty system TODO który dopisuje zadania do pliku.
Operacje na wielu plikach
- Skopiuj zawartość jednego pliku do drugiego.
- Połącz dwa pliki tekstowe w jeden.
- Odczytaj plik, zamień wszystkie litery na wielkie i zapisz do nowego pliku.
- Odczytaj plik, usuń puste linie i zapisz do nowego pliku.
- Odczytaj plik, ponumeruj linie i zapisz do nowego pliku.
Przetwarzanie danych
- Odczytaj plik z liczbami (każda w linii) i oblicz ich sumę.
- Odczytaj plik z liczbami i znajdź największą oraz najmniejszą.
- Odczytaj plik tekstowy i stwórz plik ze statystykami (liczba linii, słów, znaków).
- Odczytaj plik i zapisz tylko linie dłuższe niż 50 znaków do nowego pliku.
- Odczytaj plik i zapisz linie w odwrotnej kolejności do nowego pliku.
Filtrowanie i wyszukiwanie
- Znajdź i wyświetl wszystkie linie zawierające „@” (adresy email).
- Skopiuj do nowego pliku tylko linie zaczynające się od „#” (komentarze).
- Odczytaj plik logu i zapisz do nowego tylko linie zawierające „ERROR”.
- Znajdź wszystkie linie zawierające liczby i zapisz je osobno.
- Usuń z pliku wszystkie linie zawierające konkretne słowo.
Praca ze ścieżkami (moduł os)
- Wyświetl bieżący katalog roboczy.
- Wyświetl listę wszystkich plików w bieżącym katalogu.
- Sprawdź czy plik o podanej nazwie istnieje.
- Wyświetl listę wszystkich plików .txt w katalogu.
- Policz ile plików znajduje się w katalogu.
Obsługa błędów
- Spróbuj otworzyć nieistniejący plik i obsłuż błąd.
- Napisz funkcję która bezpiecznie odczytuje plik (obsługuje błędy).
- Sprawdź czy plik istnieje przed próbą otwarcia.
- Obsłuż błąd braku uprawnień do pliku.
- Napisz funkcję która próbuje otworzyć plik 3 razy przed poddaniem się.
Funkcje do pracy z plikami
- Napisz funkcję
zapisz_liste(lista, nazwa_pliku)która zapisuje listę do pliku. - Napisz funkcję
wczytaj_liste(nazwa_pliku)która wczytuje listę z pliku. - Napisz funkcję
policz_linie(nazwa_pliku)która zwraca liczbę linii. - Napisz funkcję
znajdz_w_pliku(nazwa_pliku, szukane)która znajduje i zwraca linie zawierające szukany tekst. - Napisz funkcję
usun_duplikaty(plik_wejsciowy, plik_wyjsciowy)która usuwa powtarzające się linie.
CSV i dane strukturalne
- Zapisz listę słowników do pliku CSV (bez modułu csv).
- Odczytaj plik CSV i wyświetl dane w formacie tabelarycznym.
- Stwórz plik CSV z danymi uczniów (imię, nazwisko, klasa, średnia).
- Odczytaj plik CSV i znajdź ucznia z najwyższą średnią.
- Stwórz plik CSV z cenami produktów. Oblicz wartość całego magazynu.
JSON
- Zapisz słownik do pliku JSON.
- Odczytaj dane z pliku JSON.
- Zapisz listę słowników (dane użytkowników) do pliku JSON.
- Odczytaj JSON, zmodyfikuj dane i zapisz z powrotem.
- Stwórz bazę danych kontaktów w formacie JSON.
Pliki binarne
- Skopiuj plik binarny (np. obrazek).
- Sprawdź rozmiar pliku binarnego w bajtach.
- Odczytaj pierwsze 100 bajtów z pliku binarnego.
- Porównaj rozmiary pliku tekstowego i tego samego pliku skompresowanego.
- Napisz funkcję która sprawdza typ pliku na podstawie rozszerzenia.
Logowanie
- Stwórz prosty system logowania który zapisuje logi z datą i czasem.
- Napisz funkcję
log(wiadomosc, poziom)która loguje z poziomami (INFO, WARNING, ERROR). - Stwórz osobne pliki logów dla różnych poziomów.
- Ogranicz rozmiar pliku logu – jeśli przekroczy 1000 linii, zacznij nowy plik.
- Napisz funkcję która wyświetla ostatnie 10 linii z logu.
Kontakty/Książka adresowa
- Stwórz system dodawania kontaktów do pliku (imię, telefon, email).
- Napisz funkcję wyświetlającą wszystkie kontakty z pliku.
- Napisz funkcję wyszukującą kontakt po imieniu.
- Napisz funkcję usuwającą kontakt.
- Napisz funkcję edytującą kontakt.
TODO list
- Stwórz prosty system TODO z zapisem do pliku.
- Dodaj możliwość oznaczania zadań jako wykonane.
- Dodaj priorytet zadań (niski, średni, wysoki).
- Wyświetl tylko zadania nieukończone.
- Posortuj zadania według priorytetu.
Statystyki i analizy
- Napisz funkcję analizującą plik tekstowy (najczęstsze słowo, najdłuższe słowo, średnia długość słowa).
- Policz wystąpienia każdej litery w pliku.
- Stwórz histogram długości słów w pliku.
- Znajdź wszystkie unikalne słowa w pliku.
- Policz ile razy każde słowo występuje w pliku (użyj Counter).
Backup i archiwizacja
- Napisz funkcję tworzącą kopię zapasową pliku (dopisz datę do nazwy).
- Stwórz funkcję która zapisuje historię zmian w pliku.
- Napisz funkcję która przywraca plik z backupu.
- Stwórz rotację backupów – zachowaj tylko 5 najnowszych.
- Napisz funkcję porównującą dwa pliki i wyświetlającą różnice.
Konfiguracja
- Stwórz plik konfiguracyjny (nazwa=wartość w każdej linii) i funkcje do odczytu.
- Napisz funkcję zapisującą ustawienia do pliku konfiguracyjnego.
- Stwórz domyślną konfigurację jeśli plik nie istnieje.
- Waliduj konfigurację podczas wczytywania.
- Dodaj komentarze do pliku konfiguracyjnego (linie zaczynające się od #).
Raportowanie
- Napisz funkcję generującą raport HTML z danymi z pliku.
- Stwórz raport zawierający statystyki z wielu plików.
- Wygeneruj raport CSV z podsumowaniem danych.
- Stwórz raport tekstowy z formatowaniem (ramki, wyrównanie).
- Napisz funkcję która generuje raport porównawczy z dwóch plików.
Zadania kompleksowe
- Stwórz prosty system zarządzania uczniami: dodawanie, usuwanie, edycja, wyświetlanie, zapisywanie do pliku.
- Napisz program do analizy logów serwera: zlicz błędy, ostrzeżenia, wyświetl statystyki.
- Stwórz system inwentaryzacji: produkty z ilościami, cenami, raport wartości magazynu.
- Napisz program do zarządzania wydatkami: dodawanie wydatków, kategorie, raporty miesięczne, zapis do pliku.
- Stwórz system rezerwacji: terminy, zarezerwowane/wolne, zapis do pliku, walidacja.
- Napisz grę tekstową która zapisuje stan gry do pliku i pozwala wczytać zapisany stan.
- Stwórz prosty system blogowy: posty z datą, tytułem, treścią, zapisywanie do plików.
- Napisz konwerter między formatami (TXT ↔ CSV ↔ JSON).
- Stwórz system punktacji quizu z zapisem wyników do pliku i rankingiem.
- Napisz program szyfrujący i deszyfrujący pliki tekstowe (np. szyfr Cezara).