Vai al contenuto
Leo

Parte III — Organizzare

Capitolo 13 — File e cartelle

I programmi visti finora dimenticano tutto quando finiscono: i dati vivono in memoria e svaniscono alla chiusura. Per ricordare tra un'esecuzione e l'altra — salvare una lista di cose da fare, leggere un file di configurazione, produrre un rapporto — bisogna scrivere su disco. Leo rende l'operazione diretta, con qualche attenzione in più che ti risparmia grattacapi.

🦁 Curiosità — Un disco da una tonnellata per 5 MB

Il primo disco rigido della storia, l'IBM 350 del 1956, era alto come un armadio e pesava quasi una tonnellata, eppure conteneva soltanto circa 5 MB: oggi una singola foto scattata col telefono può occupare più spazio di così. Per spostarlo serviva un carrello elevatore; per spostare le tue foto basta un dito. La capacità di «ricordare su disco» è diventata enormemente più leggera in meno di settant'anni.

Una nota prima di cominciare: i percorsi relativi ("nota.txt") partono dalla cartella da cui lanci il programma. Le cartelle si separano con la barra /, anche su Windows.

💡 L'idea — Il percorso è un indirizzo

Il percorso di un file (la sua path) funziona come l'indirizzo di casa: provincia, città, via, numero civico restringono il campo un pezzo alla volta, finché non arrivi alla porta giusta. Così documenti/2026/nota.txt è «cartella documenti, dentro la cartella 2026, il file nota.txt». Una volta che leggi un percorso come un indirizzo, non ti perdi più nell'albero delle cartelle.

Leggere e scrivere testo

Le due operazioni fondamentali sono scrivere un testo in un file e rileggerlo:

Leo
scrivi_file("nota.txt", "Prima riga\nSeconda riga")
aggiungi_a_file("nota.txt", "Terza riga")
variabile contenuto = leggi_file("nota.txt")
scrivi "--- contenuto ---"
scrivi(contenuto)
scrivi "--- righe ---"
per ogni riga in leggi_righe("nota.txt") fai
    scrivi "> {riga}"
fine
scrivi "Esiste nota.txt? {esiste("nota.txt")}"
scrivi "Esiste manca.txt? {esiste("manca.txt")}"
Risultato
--- contenuto ---
Prima riga
Seconda riga
Terza riga

--- righe ---
> Prima riga
> Seconda riga
> Terza riga
Esiste nota.txt? vero
Esiste manca.txt? falso

scrivi_file(percorso, testo) crea il file (o ne sostituisce il contenuto, se esiste già). aggiungi_a_file(percorso, testo) aggiunge in fondo senza cancellare — comodo per un registro che cresce nel tempo — e va a capo da sé. leggi_file(percorso) restituisce tutto il contenuto come un unico testo; leggi_righe(percorso) lo dà invece come lista di righe, già senza i caratteri di a-capo, perfetto per scorrerle con per ogni. Infine esiste(percorso) controlla se un file (o una cartella) c'è prima di toccarlo.

Dietro questa semplicità c'è parecchia cura. leggi_file riconosce da solo la codifica del testo (UTF-8, i formati Unicode del Blocco note, la codifica di Excel su Windows) e normalizza gli a-capo di Windows. Se provi a leggere come testo un file che non lo è — un'immagine, un programma — ottieni un ErroreFile in italiano invece di caratteri illeggibili. E su Windows i nomi di file vietati vengono rifiutati con una spiegazione, prima ancora di aprire il file.

JSON e CSV: dati strutturati

Il testo libero va bene per le note; per i dati strutturati — liste di dizionari, tabelle — ci sono formati dedicati, e Leo li legge e scrive con una riga. Il JSON è lo standard per scambiare dati tra programmi:

Leo
variabile persone = [
    {"nome": "Ada", "eta": 36},
    {"nome": "Marco", "eta": 29}
]
scrivi_json("persone.json", persone)
variabile lette = leggi_json("persone.json")
per ogni p in lette fai
    scrivi "{p["nome"]} ha {p["eta"]} anni"
fine
Risultato
Ada ha 36 anni
Marco ha 29 anni

scrivi_json trasforma una struttura Leo (liste, dizionari, numeri, testi) in un file JSON ben formattato, e leggi_json fa il percorso inverso, restituendo di nuovo liste e dizionari pronti all'uso. Il bello è che il dato che rileggi è identico a quello che hai salvato: niente conversioni manuali.

Per le tabelle in stile foglio di calcolo c'è il CSV, che Excel e gli altri programmi d'ufficio capiscono:

Leo
scrivi_tabella("persone.csv", persone)
scrivi(leggi_file("persone.csv"))
Risultato
nome,eta
Ada,36
Marco,29

scrivi_tabella prende una lista di dizionari e ne fa un CSV, mettendo in cima i nomi delle colonne. C'è anche leggi_tabella, che fa il contrario e indovina da solo il separatore (virgola, punto e virgola o tabulazione). Vedremo nel tour della libreria che esiste anche un tipo tabella più potente, con filtri, ordinamenti e raggruppamenti.

Lavorare con le cartelle

Oltre ai singoli file, puoi creare cartelle ed elencarne il contenuto:

Leo
crea_cartella("sotto")
scrivi_file("sotto/a.txt", "a")
scrivi_file("sotto/b.txt", "b")
scrivi(elenca_file("sotto"))
Risultato
["a.txt", "b.txt"]

crea_cartella crea la cartella (e quelle intermedie, se nel percorso ce ne sono di mancanti). elenca_file(cartella) restituisce i nomi dei file in ordine alfabetico; puoi anche filtrarli per estensione. C'è il gemello elenca_cartelle per le sottocartelle. Con questi mattoni puoi scrivere programmi che riordinano una cartella, elaborano tutti i file di un certo tipo o costruiscono un indice.

🦁 Curiosità — Nomi presi in prestito dall'ufficio di carta

Parole come «file» (in inglese, l'archivio di documenti), «cartella» e «cestino» non sono nate col computer: vengono dritte dall'ufficio di carta. Chi progettò le prime interfacce grafiche copiò di proposito la scrivania, le cartelline e il cestino della spazzatura, per rendere familiare una cosa del tutto nuova. Ancora oggi buttiamo i file nel «cestino»: una metafora di carta sopravvissuta dentro lo schermo.

Un esempio che mette tutto insieme

Pensa a un piccolo diario: a ogni esecuzione aggiunge una riga con la data e un pensiero, e poi mostra tutto quello che hai scritto finora. Scrivere, aggiungere, rileggere e scorrere: con aggiungi_a_file e leggi_righe lo costruisci in pochissime righe. Questo è il momento in cui i tuoi programmi smettono di essere esercizi e cominciano a servire a qualcosa, perché ricordano.

Prova tu

  1. Scrivi un programma «diario» che chiede un pensiero all'utente, lo aggiunge a un file con la data di oggi (usa oggi()), poi stampa tutte le righe scritte finora.
  2. Salva in JSON una piccola rubrica (nome, telefono, email per ogni contatto), poi scrivi un secondo programma che la rilegge e la stampa ordinata per nome.
  3. Scrivi un programma che crea una cartella backup, vi copia dentro il contenuto di un file di testo esistente, e conferma stampando l'elenco dei file nella cartella.

Con questo si chiude la Parte III. Sai organizzare il codice in oggetti e moduli, e far sì che i tuoi programmi ricordino i dati su disco. Nella Parte IV alziamo il tiro: parallelismo, sequenze pigre e il grande catalogo della libreria.