W3docs

Leggere File in Python – Guida Completa

Impara tutti i modi per leggere file in Python: read(), readline(), readlines(), iterazione, modalità binaria, encoding e pathlib.

Leggere file è una delle operazioni più comuni in Python — che si tratti di caricare configurazioni, elaborare log, importare dati CSV o leggere risorse binarie. Questo capitolo tratta tutti i metodi che Python offre per leggere il contenuto di un file: dalla più semplice chiamata read() all'iterazione riga per riga efficiente in termini di memoria, alla modalità binaria, alla gestione dell'encoding, al controllo della posizione nel file e alla moderna API pathlib.

Aprire un File in Lettura

Ogni operazione su file inizia con la funzione built-in open(). Per aprire un file in modalità lettura, usa la stringa di modalità "r" (che è quella predefinita quando non viene specificata alcuna modalità):

file_object = open("notes.txt", "r", encoding="utf-8")
  • "r" — apre in lettura; solleva FileNotFoundError se il file non esiste.
  • encoding="utf-8" — specifica sempre la codifica dei caratteri per i file di testo in modo che il tuo codice funzioni in modo identico su Windows, macOS e Linux.

Usa Sempre un Blocco with

Il modo più sicuro per aprire un file è all'interno di un'istruzione with. Python chiude automaticamente il file quando il blocco termina — anche se si verifica un'eccezione — il che previene perdite di risorse e garantisce che i dati in buffer vengano scritti.

with open("notes.txt", "r", encoding="utf-8") as f:
    contents = f.read()
# File is automatically closed here

Chiamare open() al di fuori di un blocco with e dimenticare file.close() è una fonte frequente di errori "too many open files" negli script a lunga esecuzione.

Leggere l'Intero File con read()

read() restituisce il contenuto completo del file come una singola string.

Leggere un intero file in una volta

with open("notes.txt", "r", encoding="utf-8") as f:
    contents = f.read()

print(contents)

Usa read() quando:

  • Il file è abbastanza piccolo da stare comodamente in memoria.
  • Hai bisogno del testo completo come una singola string (ad es. per il parsing o la ricerca).

Per file che potrebbero essere grandi (log, dump di dati), preferisci gli approcci riga per riga descritti di seguito.

Leggere un Numero Fisso di Caratteri

Passa un intero n a read(n) per leggere al massimo n caratteri dalla posizione corrente. Le chiamate successive a read(n) continuano da dove si era fermata l'ultima lettura.

Leggere i primi 50 caratteri

with open("notes.txt", "r", encoding="utf-8") as f:
    first_chunk = f.read(50)
    second_chunk = f.read(50)

print(repr(first_chunk))
print(repr(second_chunk))

Questo approccio a blocchi è utile quando vuoi visualizzare un'anteprima di un file o elaborarlo in pezzi di dimensione fissa senza caricare tutto in memoria.

Leggere una Riga alla Volta con readline()

readline() legge una riga dal file, incluso il carattere di a capo finale \n. Restituisce una string vuota "" quando viene raggiunta la fine del file, il che rende facile eseguire un ciclo fino all'EOF.

Leggere un file riga per riga con readline()

with open("notes.txt", "r", encoding="utf-8") as f:
    line = f.readline()
    while line:
        print(line, end="")   # line already contains '\n'
        line = f.readline()

L'argomento end="" in print() previene la comparsa di una doppia riga vuota (una dalla riga del file e una dal comportamento predefinito di print).

readline() è utile quando devi elaborare una riga di intestazione in modo diverso dal resto, o quando vuoi interrompere la lettura a metà del file in base a una condizione.

Iterazione sulle Righe (il Modo più Pythonico)

Iterare direttamente su un oggetto file è il modo più idiomatico ed efficiente in termini di memoria per elaborare un file di testo riga per riga. Python legge una riga alla volta senza caricare l'intero file in memoria.

Iterare sulle righe con un ciclo for

with open("notes.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line, end="")

Questo pattern è preferibile rispetto a read() + split("\n") e rispetto alla chiamata di readline() in un ciclo while, perché è più breve e gestisce correttamente tutti i casi limite (inclusi i file che non terminano con una riga vuota).

Cercare un pattern durante l'iterazione

with open("server.log", "r", encoding="utf-8") as f:
    for line in f:
        if "ERROR" in line:
            print(line, end="")

Leggere Tutte le Righe in una Lista con readlines()

readlines() restituisce una lista in cui ogni elemento è una riga del file (con il carattere di a capo incluso). Questo carica l'intero file in memoria.

Leggere tutte le righe in una lista

with open("notes.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

print(lines[0])        # first line
print(lines[-1])       # last line
print(len(lines))      # total number of lines

Usa readlines() quando hai bisogno di accesso casuale a righe specifiche tramite indice. Per l'elaborazione sequenziale dall'alto verso il basso, il pattern for line in f è più efficiente in termini di memoria.

Rimuovere i Caratteri di A Capo

Le righe restituite da readline(), readlines() e dall'iterazione con il ciclo for includono tutte il \n finale. Usa .strip() o .rstrip("\n") per rimuoverlo:

with open("notes.txt", "r", encoding="utf-8") as f:
    lines = [line.rstrip("\n") for line in f]

print(lines)  # ['Line one', 'Line two', 'Line three']

Scegliere il Metodo di Lettura Giusto

MetodoRestituisceCarica l'intero file?Ideale per
f.read()strFile piccoli, parsing di testo completo
f.read(n)strNo (a blocchi)Streaming a dimensione fissa
f.readline()strNoInterruzioni condizionali riga per riga
for line in fstr (uno per iterazione)NoElaborazione sequenziale delle righe
f.readlines()list[str]Accesso casuale per indice alle righe

Posizione nel File: tell() e seek()

Ogni oggetto file aperto mantiene un puntatore di posizione interno che avanza durante la lettura. Due metodi consentono di ispezionarlo e controllarlo:

  • tell() — restituisce l'offset in byte corrente dall'inizio del file.
  • seek(offset, whence=0) — sposta il puntatore. Con whence=0 (predefinito) l'offset è dall'inizio; whence=1 è dalla posizione corrente; whence=2 è dalla fine.

Leggere un file due volte usando seek(0)

with open("notes.txt", "r", encoding="utf-8") as f:
    first_pass = f.read()
    print(f"Position after first read: {f.tell()}")

    f.seek(0)   # rewind to the beginning
    second_pass = f.read()

print(first_pass == second_pass)  # True

seek() è particolarmente utile in modalità "r+" (lettura-scrittura), dove potresti leggere una sezione di un file e poi sovrascrivere una parte specifica nella stessa chiamata open().

Gestione degli Errori durante la Lettura

Uno script ben scritto anticipa sempre i modi in cui una lettura di file può fallire.

Gestire gli errori di lettura più comuni

try:
    with open("data.txt", "r", encoding="utf-8") as f:
        content = f.read()
except FileNotFoundError:
    print("Error: the file does not exist.")
except PermissionError:
    print("Error: you do not have permission to read this file.")
except UnicodeDecodeError:
    print("Error: the file contains bytes that are not valid UTF-8.")
except OSError as e:
    print(f"OS error: {e}")

Eccezioni comuni che incontrerai:

EccezioneQuando si verifica
FileNotFoundErrorIl percorso non punta a un file esistente
PermissionErrorIl processo non ha il permesso di lettura
IsADirectoryErrorIl percorso punta a una directory, non a un file
UnicodeDecodeErrorI byte del file non corrispondono all'encoding specificato

Vedi Python Try Except per una guida completa alla gestione delle eccezioni.

Codifica dei Caratteri

Quando Python apre un file in modalità testo, deve sapere come convertire i byte grezzi in caratteri. Passa sempre encoding= esplicitamente anziché affidarti al valore predefinito della piattaforma, che differisce tra Windows (cp1252) e la maggior parte dei sistemi Unix (utf-8).

Valori di encoding comuni:

EncodingUsa quando
"utf-8"File moderni, contenuto web, la maggior parte dei progetti Python
"utf-8-sig"File UTF-8 creati da strumenti Windows che antepongono un BOM
"latin-1"File Western-European legacy
"cp1252"File di testo ANSI di Windows

Rilevare o ignorare i problemi di encoding:

Se non sei sicuro dell'encoding di un file, puoi dire a Python di sostituire i byte non decodificabili con un segnaposto anziché sollevare un errore:

with open("mystery.txt", "r", encoding="utf-8", errors="replace") as f:
    content = f.read()

Altri valori per errors includono "ignore" (ignora silenziosamente i byte non validi) e "strict" (predefinito — solleva UnicodeDecodeError).

Leggere File Binari

Apri un file in modalità binaria aggiungendo "b" alla stringa di modalità ("rb"). La modalità binaria restituisce oggetti bytes grezzi anziché string, il che è corretto per immagini, audio, archivi compressi, eseguibili e qualsiasi dato non testuale.

Leggere un file binario

with open("photo.jpg", "rb") as f:
    data = f.read()

print(type(data))   # <class 'bytes'>
print(len(data))    # size in bytes

Copiare un file binario

with open("photo.jpg", "rb") as src:
    data = src.read()

with open("photo_backup.jpg", "wb") as dst:
    dst.write(data)

Non specificare encoding in modalità binaria — Python solleva ValueError se ci provi.

Leggere File di Grandi Dimensioni in Modo Efficiente

Caricare un file da diversi gigabyte con read() può esaurire la memoria di sistema. Le soluzioni sono:

Iterazione riga per riga (file di testo)

with open("huge_log.txt", "r", encoding="utf-8") as f:
    for line in f:
        process(line)   # only one line in memory at a time

Blocchi di dimensione fissa (file binari)

CHUNK_SIZE = 65536  # 64 KB

with open("large_file.bin", "rb") as f:
    while True:
        chunk = f.read(CHUNK_SIZE)
        if not chunk:
            break
        process(chunk)

Entrambi i pattern mantengono l'utilizzo della memoria costante indipendentemente dalla dimensione del file.

Leggere File con pathlib

Python 3.4 ha introdotto pathlib.Path, che fornisce un'interfaccia orientata agli oggetti per i percorsi del file system. Per letture e scritture semplici in un'unica operazione, gli oggetti Path sono più concisi di open().

Leggere testo con Path.read_text()

from pathlib import Path

content = Path("notes.txt").read_text(encoding="utf-8")
print(content)

Leggere byte con Path.read_bytes()

from pathlib import Path

data = Path("photo.jpg").read_bytes()
print(len(data))  # file size in bytes

read_text() e read_bytes() aprono il file, ne leggono l'intero contenuto e lo chiudono in un'unica chiamata. Usali per file piccoli quando hai solo bisogno del contenuto. Usa open() con un blocco with quando hai bisogno dell'iterazione riga per riga, della lettura a blocchi, di seek() o di qualsiasi altro controllo granulare.

Verificare che un File Esista Prima di Leggerlo

from pathlib import Path

p = Path("data.txt")
if p.exists() and p.is_file():
    content = p.read_text(encoding="utf-8")
else:
    print("File not found.")

Nota: p.exists() può restituire un risultato non aggiornato nel codice multi-thread. In questi casi è più sicuro tentare la lettura e intercettare FileNotFoundError.

Esempio Pratico: Leggere un Semplice File di Configurazione

Molti script leggono un file di configurazione in testo semplice che memorizza una coppia key=value per riga. Ecco un esempio completo e funzionante:

Analizzare un file di configurazione key=value

from pathlib import Path

def load_config(path):
    config = {}
    with open(path, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith("#"):
                continue          # skip blank lines and comments
            key, _, value = line.partition("=")
            config[key.strip()] = value.strip()
    return config

# Example config.txt contents:
# host = localhost
# port = 8080
# debug = true

config = load_config("config.txt")
# config == {'host': 'localhost', 'port': '8080', 'debug': 'true'}

str.partition("=") divide solo sul primo =, quindi i valori che contengono = (come le string Base64) vengono gestiti correttamente.

Capitoli Correlati

Was this page helpful?