Scrivere e creare file in Python
Impara a scrivere file in Python con write(), writelines(), modalità append, scritture binarie, pathlib, codifica e pattern sicuri con i blocchi with.
La scrittura di file è una delle operazioni di I/O più fondamentali in Python. Che si tratti di salvare l'output di un programma, persistere configurazioni, esportare dati in CSV o registrare eventi, è necessario un modo affidabile per creare e aggiornare file. Questo capitolo copre ogni approccio fornito da Python: write(), writelines(), modalità append, scritture binarie, gestione dei newline, codifica dei caratteri, la moderna API pathlib e i pattern per scrivere in modo sicuro senza perdita di dati.
Aprire un file per la scrittura
Ogni operazione di scrittura su file inizia con la funzione built-in open(). Il secondo argomento — la modalità — controlla cosa accade quando si apre il file:
| Modalità | Significato | File esistente | File mancante |
|---|---|---|---|
"w" | Scrittura (testo) | Tronca (cancella) il file | Crea un nuovo file |
"a" | Append (testo) | Sposta il puntatore alla fine | Crea un nuovo file |
"x" | Creazione esclusiva | Solleva FileExistsError | Crea un nuovo file |
"wb" | Scrittura (binario) | Tronca il file | Crea un nuovo file |
"ab" | Append (binario) | Sposta il puntatore alla fine | Crea un nuovo file |
"r+" | Lettura + scrittura | Apre nella posizione attuale | Solleva FileNotFoundError |
La cosa più importante da ricordare riguardo alla modalità "w": cancella silenziosamente l'intero file prima di scrivere. Se si desidera solo aggiungere contenuto a un file esistente, usare invece la modalità "a" (append).
Fornire sempre il parametro encoding quando si scrivono file di testo, in modo che il codice si comporti in modo identico su Windows, macOS e Linux:
file = open("output.txt", "w", encoding="utf-8")Usare sempre un blocco with
Chiamare open() senza un blocco with significa dover chiamare file.close() manualmente. Dimenticarsi di chiudere un file porta a dati bufferizzati che non vengono mai scritti su disco, errori di troppi file aperti in script a lunga esecuzione e corruzione del file su alcuni sistemi operativi.
L'istruzione with (un context manager) risolve tutti questi problemi. Python chiude il file automaticamente quando il blocco termina — anche se viene sollevata un'eccezione all'interno del blocco.
with open("output.txt", "w", encoding="utf-8") as f:
f.write("Hello, World!\n")
# File is closed and flushed here — guaranteedTutti gli esempi in questo capitolo usano l'istruzione with. Evitare il pattern manuale open() / close().
Scrivere testo con write()
file.write(string) scrive la stringa data nel file e restituisce il numero di caratteri scritti. Non aggiunge automaticamente un newline — occorre includere \n manualmente.
Scrivere una singola riga in un nuovo file
with open("greeting.txt", "w", encoding="utf-8") as f:
chars_written = f.write("Hello, World!\n")
print(chars_written) # 14Scrivere più righe chiamando write() ripetutamente
with open("poem.txt", "w", encoding="utf-8") as f:
f.write("Roses are red,\n")
f.write("Violets are blue,\n")
f.write("Python is great,\n")
f.write("And so are you.\n")Ogni chiamata a write() aggiunge al file nella posizione corrente. Il file viene scritto da zero (qualsiasi contenuto precedente viene eliminato) perché è stata usata la modalità "w".
Scrivere più righe con writelines()
file.writelines(iterable) accetta qualsiasi iterabile di stringhe — una lista, un generatore o una tupla — e scrive ogni elemento in sequenza. Come write(), non aggiunge newline tra gli elementi.
Scrivere una lista di righe
lines = [
"First line\n",
"Second line\n",
"Third line\n",
]
with open("lines.txt", "w", encoding="utf-8") as f:
f.writelines(lines)Se i dati sorgente non contengono già \n, aggiungerlo prima di scrivere:
data = ["Alice", "Bob", "Charlie"]
with open("names.txt", "w", encoding="utf-8") as f:
f.writelines(name + "\n" for name in data)L'espressione generatrice name + "\n" for name in data è efficiente in termini di memoria: Python produce ogni stringa su richiesta invece di costruire l'intera lista in memoria prima.
write() vs writelines() — Quando usare ciascuno
write() | writelines() | |
|---|---|---|
| Input | Una singola stringa | Qualsiasi iterabile di stringhe |
| Newline | Si controlla ogni \n | Si controlla ogni \n |
| Ideale per | Costruire l'output in modo incrementale | Scrivere una sequenza pre-costruita in una volta sola |
Creare un file che non deve già esistere
Usare la modalità "x" (creazione esclusiva) quando si vuole che Python crei un nuovo file e fallisca se il file esiste già. Questo previene la sovrascrittura accidentale di dati importanti.
try:
with open("config.txt", "x", encoding="utf-8") as f:
f.write("host=localhost\n")
f.write("port=8080\n")
except FileExistsError:
print("config.txt already exists — not overwriting.")Questo pattern è utile per generare file di output univoci (log, esportazioni, snapshot) dove una collisione indica che qualcosa è andato storto.
Aggiungere contenuto a un file esistente
Aprire un file con la modalità "a" sposta il puntatore di scrittura alla fine del file. Il nuovo contenuto viene aggiunto dopo quello esistente; nulla viene cancellato.
Aggiungere una voce di log a un file esistente
import datetime
with open("app.log", "a", encoding="utf-8") as f:
timestamp = datetime.datetime.now().isoformat()
f.write(f"[{timestamp}] Server started\n")Se app.log non esiste ancora, Python lo crea. Se esiste, la nuova riga viene aggiunta alla fine. Eseguire lo script più volte accumula un log crescente.
Write vs Append — Scegliere la modalità giusta
- Usare
"w"quando si vuole sostituire interamente il contenuto del file (generare un report aggiornato, salvare una nuova configurazione). - Usare
"a"quando si vuole aggiungere al contenuto esistente (logging, accumulo di risultati su più esecuzioni).
Newline e terminazioni di riga
La modalità testo di Python ("w", "a", "r") traduce il newline universale \n nella terminazione di riga nativa della piattaforma in scrittura:
- Windows:
\n→\r\n(CRLF) - macOS / Linux:
\nrimane\n(LF)
Questo è di solito il comportamento corretto — i file scritti su Windows si aprono correttamente in Notepad.
Se si ha bisogno di forzare una terminazione di riga specifica indipendentemente dalla piattaforma — ad esempio quando si generano file che devono essere letti da un sistema specifico — passare il parametro newline:
# Force Unix-style LF on all platforms (e.g. for Linux-target files)
with open("unix_file.txt", "w", encoding="utf-8", newline="\n") as f:
f.write("line one\n")
f.write("line two\n")
# Preserve line endings exactly as given (no translation at all)
with open("raw.txt", "w", encoding="utf-8", newline="") as f:
f.write("line one\r\n")
f.write("line two\n")Codifica dei caratteri
Specificare sempre encoding= quando si scrivono file di testo. Fare affidamento sull'impostazione predefinita della piattaforma rischia di creare file che non possono essere letti su altri sistemi.
Codifiche consigliate per scenari comuni:
| Codifica | Da usare quando |
|---|---|
"utf-8" | Uso generale; funziona per tutte le lingue; predefinita per la maggior parte dei progetti Python |
"utf-8-sig" | UTF-8 con BOM — utile per file che verranno aperti in Excel su Windows |
"latin-1" | File legacy dell'Europa occidentale |
"cp1252" | Testo ANSI di Windows |
Scrivere un file con codifica UTF-8
with open("international.txt", "w", encoding="utf-8") as f:
f.write("English: Hello\n")
f.write("Japanese: こんにちは\n")
f.write("Arabic: مرحبا\n")Scrivere file binari
Aprire un file con la modalità "wb" (write binary) per scrivere byte grezzi invece di stringhe. La modalità binaria è richiesta per immagini, audio, archivi compressi, eseguibili e qualsiasi dato non testuale. Non specificare encoding in modalità binaria.
Scrivere byte in un file binario
data = bytes([0x89, 0x50, 0x4E, 0x47]) # PNG magic bytes
with open("header.bin", "wb") as f:
f.write(data)
print(f.write(b"\r\n\x1a\n")) # 4Copiare un file binario
with open("photo.jpg", "rb") as src:
content = src.read()
with open("photo_backup.jpg", "wb") as dst:
dst.write(content)Per file binari di grandi dimensioni, leggere e scrivere a blocchi per evitare di caricare l'intero file in memoria:
CHUNK = 65536 # 64 KB
with open("large.bin", "rb") as src, open("large_copy.bin", "wb") as dst:
while True:
chunk = src.read(CHUNK)
if not chunk:
break
dst.write(chunk)Gestire gli errori durante la scrittura
Uno script di qualità produttiva anticipa sempre i modi in cui una scrittura su file può fallire.
Gestire gli errori di scrittura più comuni
try:
with open("/etc/protected.txt", "w", encoding="utf-8") as f:
f.write("data\n")
except PermissionError:
print("Error: you do not have write permission for this file.")
except FileNotFoundError:
print("Error: one or more directories in the path do not exist.")
except IsADirectoryError:
print("Error: the path points to a directory, not a file.")
except OSError as e:
print(f"OS error: {e}")Eccezioni comuni che si possono incontrare:
| Eccezione | Quando si verifica |
|---|---|
PermissionError | Il processo non ha i permessi di scrittura |
FileNotFoundError | Una directory intermedia nel percorso non esiste |
FileExistsError | Modalità "x" e il file esiste già |
IsADirectoryError | Il percorso punta a una directory |
OSError | Disco pieno, errore del filesystem di rete e altri problemi a livello OS |
Consultare Python Try Except per una guida completa alla gestione delle eccezioni.
Scrivere file in modo sicuro (pattern di scrittura atomica)
Un semplice open("file.txt", "w") non è sicuro per dati critici: se lo script si blocca o viene interrotto a metà scrittura, il file viene lasciato in uno stato parzialmente scritto e corrotto. La soluzione standard è una scrittura atomica: scrivere prima in un file temporaneo, poi rinominarlo sovrascrivendo il file di destinazione.
import os
import tempfile
def write_file_safely(path, content, encoding="utf-8"):
"""Write content to path atomically using a temp file + rename."""
dir_name = os.path.dirname(os.path.abspath(path)) or "."
# Write to a temp file in the same directory (same filesystem = atomic rename)
fd, tmp_path = tempfile.mkstemp(dir=dir_name)
try:
with os.fdopen(fd, "w", encoding=encoding) as f:
f.write(content)
os.replace(tmp_path, path) # atomic on POSIX; best-effort on Windows
except Exception:
os.unlink(tmp_path) # clean up if something went wrong
raise
write_file_safely("important.txt", "critical data\n")os.replace() (Python 3.3+) sostituisce la destinazione in modo atomico sui sistemi POSIX: i lettori vedono il file vecchio o quello nuovo, mai una scrittura parziale.
Scrivere file con pathlib
pathlib.Path (introdotto in Python 3.4) fornisce un'API concisa e orientata agli oggetti. Per scritture semplici in un'unica operazione, Path.write_text() e Path.write_bytes() sono più leggibili di open().
Path.write_text()
from pathlib import Path
Path("output.txt").write_text("Hello from pathlib!\n", encoding="utf-8")write_text() apre il file in modalità "w", scrive la stringa e chiude il file — tutto in una sola chiamata. Sovrascrive sempre il file. Non esiste un equivalente per l'append; per aggiungere contenuto usare open() con modalità "a".
Path.write_bytes()
from pathlib import Path
Path("data.bin").write_bytes(b"\x00\x01\x02\x03")Costruire percorsi con pathlib
pathlib rende anche facile costruire percorsi in modo sicuro senza concatenazione di stringhe:
from pathlib import Path
output_dir = Path("results")
output_dir.mkdir(exist_ok=True) # create the directory if needed
report_path = output_dir / "report.txt"
report_path.write_text("Run complete.\n", encoding="utf-8")
print(report_path) # results/report.txt
print(report_path.exists()) # TrueL'operatore / sugli oggetti Path unisce i segmenti del percorso — senza bisogno di os.path.join().
Esempio pratico: scrivere un report CSV
Il seguente esempio completo scrive una lista di record in un file CSV usando solo strumenti built-in (nessun modulo csv), dimostrando insieme diversi concetti trattati in questo capitolo.
from pathlib import Path
import datetime
def write_csv_report(path, headers, rows):
"""Write a simple CSV file with a header row."""
with open(path, "w", encoding="utf-8", newline="") as f:
f.write(",".join(headers) + "\n")
for row in rows:
f.write(",".join(str(v) for v in row) + "\n")
records = [
("Alice", 30, "Engineering"),
("Bob", 25, "Marketing"),
("Charlie", 35, "Finance"),
]
output = Path("staff_report.txt")
write_csv_report(output, ["Name", "Age", "Department"], records)
print(output.read_text(encoding="utf-8"))Output atteso:
Name,Age,Department
Alice,30,Engineering
Bob,25,Marketing
Charlie,35,FinanceNotare che newline="" viene passato a open() in modo che Python non traduca doppiamente le terminazioni di riga nelle righe CSV — questo corrisponde alla raccomandazione nella documentazione del modulo csv di Python.
Per situazioni più complesse (quoting, dialetti, casi limite Unicode) usare il modulo built-in Python CSV.
Riferimento rapido
| Obiettivo | Pattern di codice |
|---|---|
| Creare o sovrascrivere un file | open("f.txt", "w", encoding="utf-8") |
| Aggiungere a un file | open("f.txt", "a", encoding="utf-8") |
| Creare solo se nuovo | open("f.txt", "x", encoding="utf-8") |
| Scrivere dati binari | open("f.bin", "wb") |
| Scrivere una stringa | f.write("text\n") |
| Scrivere una lista di stringhe | f.writelines(lines) |
| Scrittura testo in un'unica operazione | Path("f.txt").write_text("...", encoding="utf-8") |
| Scrittura binaria in un'unica operazione | Path("f.bin").write_bytes(b"...") |
| Scrittura sicura / atomica | Scrivere in un file temporaneo, poi os.replace() |
Capitoli correlati
- Python File Handling — modalità di apertura, parametri di
open()e istruzionewith - Python Read Files —
read(),readline(),readlines(), iterazione sulle righe eseek() - Python Delete Files — eliminare file e directory in modo sicuro
- Python Try Except — gestire le eccezioni in Python
- Python CSV — leggere e scrivere file CSV con il modulo
csv - Python JSON — serializzare dati in file JSON