In un precedente approfondimento pubblicato su HTML.it, abbiamo avuto modo di spiegare cos'è il formato CSV, e come esso rappresenti uno dei modi più semplici per rappresentare dati in forma tabellare. Tale formato ha il vantaggio di basarsi sulla codifica di un semplice file di testo, ed è forse questo il principale motivo per il quale, nonostante tale formato di file sia stato uno dei primi ad essersi diffuso per l’interscambio di dati, è tuttora molto utilizzato.
In questo approfondimento ci concentreremo sulle funzionalità offerte dal linguaggio di programmazione Python per la lettura e la scritta di un file CSV. Chi non avesse chiare le peculiarità distintive del formato CSV, può fare riferimento al già citato approfondimento, per una rapida ma sufficiente infarinatura iniziale.
Aprire un file CSV con Python
In linea di principio, un file CSV non ha una struttura particolarmente complessa. Nella sua forma più classica, esso è infatti costituito da una serie di righe, ciascuna delle quali contiene un uguale numero di valori, separati tutti da una virgola. Un esempio di file CSV potrebbe essere quindi il seguente:
Nome,Cognome,Età
Mario,Rossi,20
Luigi,Bianchi,51
Clara,Esposito,18
Gennaro,Fumagalli,35
Data queste semplicissima struttura, sembrerebbe più che sufficiente gestire l'apertura del file sfruttando le funzioni ed i metodi built-in, unitamente al metodo split
delle stringhe. Con poche righe di codice, arriveremmo a qualcosa di simile a quanto segue:
try:
f = open("file.csv", "r")
for riga in f.readlines():
campi = riga.split(',')
campi[-1] = campi[-1][:-1]
#campi è una lista contenente i campi della riga corrente
for campo in campi:
print(campo, end=" ")
print("") #fine riga
f.close()
except (OSError, IOError):
#gestione degli errori
Sebbene, in linea di principio, questo parser funzioni abbastanza bene, Python fornisce uno strumento più sofisticato, rappresentato dal modulo csv. Tramite le funzioni ed i metodi definiti nel modulo csv
, possiamo gestire i file CSV in modo altrettanto semplice, ma con molte più opzioni di personalizzazione.
Vediamo subito un esempio, che produce un risultato analogo al precedente:
import csv
with open('file.csv') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for riga in csv_reader:
for campo in riga:
print(campo, end=" ")
print("") #fine riga
Questo primo esempio sfrutta ancora una volta la funzione open
, ma il file è passato come argomento alla funzione reader
definita nel modulo csv
. Tramite questa funzione, il contenuto del file è letto come CSV, ed il valore di ritorno è una sequenza iterabile mediante ciclo for
: di fatto, ad ogni iterazione leggeremo una riga, che a sua volta è anch'essa una sequenza iterabile, contenente i valori di ogni campo.
Si noti che la funzione reader
permette di specificare il delimitatore: sebbene nella sua forma originale, un file CSV dovrebbe sfruttare la sola virgola (,
), è molto ricorrente l'utilizzo di altre opzioni (il punto e virgola ;
su tutti).
È bene notare che possiamo specificare molti altri parametri: tra questi, citiamo la possibilità di definite il carattere di escape (escapechar
), quello per il quoting (quotechar
, utile per valori che contengono il delimitatore), o quello di fine riga (lineterminator
). Per ogni ulteriore dettaglio, rimandiamo alla documentazione ufficiale dedicata alla funzione reader.
Leggere in forma di dizionario
Una modifica al codice visto in precedenza ci permette di leggere il file CSV sfruttando i dizionari. Se consideriamo il file CSV di esempio visto all'inizio di questa lezione, è chiaro come ognuno dei campi che andiamo a leggere ha associato un nome. I nomi dei campi, di fatto, sono specificati dalla prima riga del file CSV.
Per sfruttare al meglio questa convenzione, dovremo procedere avvalendoci della classe DictReader
, anch'essa specificata nel modulo csv
. Vediamo subito come:
import csv
with open('file.csv', mode='r') as csv_file:
csv_reader = csv.DictReader(csv_file)
first = True
for riga in csv_reader:
if first:
#saltiamo la prima riga, quella di intestazione
first = False
continue
print(riga["Nome"], riga["Cognome"], "ha", riga["Età"], "anni")
#Mario Rossi ha 20 anni
È bene sottolineare che, nel caso in cui non ci sia una prima riga di intestazione all'interno del file CSV, quest'ultima possibilità è probabilmente da evitare.
Scrivere file CSV
Una volta appreso in che modo possiamo leggere i file CSV, vediamo in che modo il modulo csv
di Python ci permette anche di scrivere i file.
Analogamente a quanto visto in precedenza, anche in questo caso tutto si basa sull'uso di una funzione appositamente definita, che questa volta prende il nome di writer
. Vediamola subito all'opera:
import csv
with open('file.csv', mode='w') as csv_file:
csv_writer = csv.writer(csv_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
#scriviamo prima la riga di intestazione
csv_writer.writerow(['Nome', 'Cognome', 'Età'])
#aggiungiamo ora i dati
csv_writer.writerow(['Mario', 'Rossi', '20'])
csv_writer.writerow(['Luigi', 'Bianchi', '51'])
#...
Per potere scrivere un file CSV, dobbiamo specificare i diversi parametri richiesti. A parte il delimitatore (delimiter
) ed il carattere da usare per il quoting (quotechar
), dobbiamo anche specificare il parametro quoting
, per mezzo del quale definiamo la politica che Python utilizzerà per l'uso dei caratteri di quoting. Abbiamo diverse possibilità:
csv.QUOTE_MINIMAL
: il quoting sarà applicato solo se il campo contiene il delimitatore, oppure il carattere specificato inquotechar
. Questa è l'opzione predefinitacsv.QUOTE_ALL
: applica il quoting a tutti i campicsv.QUOTE_NONNUMERIC
: applica il quoting a tutti i campi che non sono numerici, e converte tutti i numeri infloat
csv.QUOTE_NONE
: non applica il quoting, optando invece per l'uso del carattere di escape
In alternativa, possiamo anche scrivere un file CSV sfruttando la classe DictWriter
, come mostrato nel seguente codice:
import csv
with open('file.csv', mode='w') as csv_file:
nome_campi = ['Nome', 'Cognome', 'Età']
writer = csv.DictWriter(csv_file, fieldnames=nome_campi)
writer.writeheader()
writer.writerow({'Nome': 'Mario', 'Cognome': 'Rossi', 'Età': 20})
writer.writerow({'Nome': 'Luigi', 'Cognome': 'Bianchi', 'Età': 51})
Quest'ultima opzione può forse sembrare più leggibile, ma ha lo svantaggio di non permettere la creazione di file CSV senza header.
Per ogni ulteriore approfondimento, rimandiamo alla pagina della documentazione ufficiale di Python.