Vai al contenuto

Gestione dei file

In questa lezione impari a

  • aprire, leggere e scrivere file con with open()
  • scegliere la modalità giusta (r, w, a)
  • gestire gli errori con try ed except
  • salvare dati strutturati in CSV e JSON

Quando un programma finisce, le variabili spariscono. Per conservare i dati bisogna scriverli in un file sul disco.

Aprire un file con with

Il modo corretto di lavorare con un file è con l'istruzione with: apre il file e lo chiude da solo alla fine del blocco, anche se succede un errore.

with open("saluti.txt", "w") as file:
    file.write("Ciao!\n")
    file.write("Seconda riga\n")

"\n" è il carattere "a capo". Il file viene creato nella stessa cartella del programma.

Le modalità di apertura

Modalità Significato Se il file non esiste Se il file esiste
"r" lettura (predefinita) errore lo legge
"w" scrittura lo crea lo cancella e riscrive
"a" aggiunta (append) lo crea scrive in fondo
"x" creazione lo crea errore

Attenzione: "w" cancella tutto il contenuto precedente senza chiedere conferma. Per aggiungere righe usa "a".

Leggere un file

with open("saluti.txt", "r") as file:
    contenuto = file.read()        # tutto il file in una stringa
print(contenuto)

with open("saluti.txt") as file:
    for riga in file:              # una riga alla volta
        print(riga.strip())

Leggere riga per riga è il metodo migliore per i file grandi, perché non carica tutto in memoria. .strip() toglie l'"a capo" finale.

Gestire gli errori: try ed except

Se il file non esiste, open() provoca un errore e il programma si blocca. Con try ed except puoi intercettare l'errore e decidere cosa fare.

try:
    with open("dati.txt") as file:
        print(file.read())
except FileNotFoundError:
    print("Il file non esiste ancora")
except PermissionError:
    print("Non hai il permesso di leggere il file")

Funziona con qualunque errore, non solo con i file:

try:
    eta = int(input("Età: "))
except ValueError:
    print("Devi scrivere un numero!")

File CSV

Un file CSV è una tabella in formato testo: ogni riga è un record, i valori sono separati da virgole. Si apre anche con Excel o con Fogli di Google.

import csv

studenti = [
    {"nome": "Anna", "classe": "3B", "media": 7.8},
    {"nome": "Luca", "classe": "3B", "media": 6.9},
]

with open("studenti.csv", "w", newline="") as file:
    scrittore = csv.DictWriter(file, fieldnames=["nome", "classe", "media"])
    scrittore.writeheader()
    scrittore.writerows(studenti)

with open("studenti.csv", newline="") as file:
    for riga in csv.DictReader(file):
        print(f"{riga['nome']}: {riga['media']}")

File JSON

JSON è il formato più usato per scambiare dati tra programmi e sul web. Somiglia moltissimo ai dizionari e alle liste di Python, e il modulo json li converte in un attimo.

import json

rubrica = {"Anna": "333 1234567", "Luca": "347 7654321"}

with open("rubrica.json", "w") as file:
    json.dump(rubrica, file, indent=2)      # salva

with open("rubrica.json") as file:
    caricata = json.load(file)              # carica
print(caricata["Anna"])

Esercizi

Esercizio 1 – Il diario. Chiedi all'utente una frase e aggiungila in fondo al file diario.txt. Poi stampa tutto il diario, con le righe numerate.

Mostra la soluzione
frase = input("Cosa è successo oggi? ")
with open("diario.txt", "a") as file:
    file.write(frase + "\n")

with open("diario.txt") as file:
    for numero, riga in enumerate(file, start=1):
        print(f"{numero}. {riga.strip()}")

Esercizio 2 – Contare le parole. Leggi un file di testo e stampa quante righe e quante parole contiene. Se il file non esiste, stampa un messaggio chiaro.

Mostra la soluzione
nome_file = input("Nome del file: ")
try:
    with open(nome_file) as file:
        righe = file.readlines()
    parole = sum(len(riga.split()) for riga in righe)
    print(f"{len(righe)} righe, {parole} parole")
except FileNotFoundError:
    print(f"Il file {nome_file} non esiste")

.split() divide una riga in parole, usando gli spazi come separatori.

Progetto finale: la rubrica che si ricorda

Riprendi la rubrica della lezione 2 e trasformala in una classe Rubrica che:

  • all'avvio carica i contatti da rubrica.json (se il file non esiste, parte vuota)
  • ha i metodi aggiungi(), cerca(), elimina() ed elenco()
  • salva su file ogni volta che i contatti cambiano

Così, quando riapri il programma, i contatti sono ancora lì. Usa tutto quello che hai imparato: dizionari, funzioni, classi, file ed eccezioni.

Mostra la soluzione
import json

class Rubrica:
    def __init__(self, nome_file="rubrica.json"):
        self.nome_file = nome_file
        try:
            with open(nome_file) as file:
                self.contatti = json.load(file)
        except FileNotFoundError:
            self.contatti = {}

    def salva(self):
        with open(self.nome_file, "w") as file:
            json.dump(self.contatti, file, indent=2)

    def aggiungi(self, nome, telefono):
        self.contatti[nome.strip().title()] = telefono.strip()
        self.salva()

    def cerca(self, nome):
        return self.contatti.get(nome.strip().title())

    def elimina(self, nome):
        nome = nome.strip().title()
        if nome in self.contatti:
            del self.contatti[nome]
            self.salva()
            return True
        return False

    def elenco(self):
        return sorted(self.contatti.items())


rubrica = Rubrica()
scelta = ""
while scelta != "0":
    print("\n1 Aggiungi  2 Cerca  3 Elimina  4 Elenco  0 Esci")
    scelta = input("Scelta: ")
    if scelta == "1":
        rubrica.aggiungi(input("Nome: "), input("Telefono: "))
    elif scelta == "2":
        numero = rubrica.cerca(input("Chi cerchi? "))
        print(numero if numero else "Contatto non trovato")
    elif scelta == "3":
        if rubrica.elimina(input("Chi elimini? ")):
            print("Eliminato")
        else:
            print("Contatto non trovato")
    elif scelta == "4":
        for nome, telefono in rubrica.elenco():
            print(f"{nome}: {telefono}")