csv - File con valori separati da virgole

Scopo Legge e scrive file con valori separati da virgole
Versione Python 2.3 e superiore

Il modulo csv è molto utile per lavorare con dati esportati in file di testo da fogli elettronici e database. Non esiste uno standard ben definito, quindi il modulo csv usa dei "dialetti" per supportare l'analisi usando parametri diversi. Assieme ad un lettore e scrittore generico, il modulo include un dialetto per lavorare con Microsoft Excel.

Limitazioni

La versione di csv in Python 2.5 non supporta i dati Unicode. Ci sono anche "problemi con i caratteri ASCII NUL". L'uso di UTF-8 o di un ASCII stampabile è raccomandato.

Lettura

Per leggere dati da un file csv si usa la funzione reader() per creare un oggetto reader. Esso può essere usato come un iteratore per elaborare le righe del file in ordine. Ad esempio:

import csv
import sys

f = open(sys.argv[1], 'rt')
try:
    reader = csv.reader(f)
    for row in reader:
        print row
finally:
    f.close()

Il primo parametro di reader() è la sorgente delle righe di testo. In questo caso si tratta di un file, ma è accettato un qualsiasi iterabile (Istanze di StringIO, liste, ecc.). Altri parametri opzionali possono essere passati per controllare come vengono analizzati i dati in input.

Il file di esempio "testdata.csv" è stato esportato da NeoOffice.

"Title 1","Title 2","Title 3"
1,"a",08/18/07
2,"b",08/19/07
3,"c",08/20/07
4,"d",08/21/07
5,"e",08/22/07
6,"f",08/23/07
7,"g",08/24/07
8,"h",08/25/07
9,"i",08/26/07

Mentre viene letta, ogni riga di dati in input viene convertita in una lista di stringhe.

$ python csv_reader.py testdata.csv
['Title 1', 'Title 2', 'Title 3']
['1', 'a', '08/18/07']
['2', 'b', '08/19/07']
['3', 'c', '08/20/07']
['4', 'd', '08/21/07']
['5', 'e', '08/22/07']
['6', 'f', '08/23/07']
['7', 'g', '08/24/07']
['8', 'h', '08/25/07']
['9', 'i', '08/26/07']

Se si sa che determinate colonne sono di un tipo specifico, si possono convertire le stringhe nell'ambito del proprio codice, ma csv non converte automaticamente l'input. Esso gestisce le interruzioni di linea incorporate nelle stringhe in una riga (ecco perchè¨ una "riga" analizzata non è sempre la stessa "riga" di input dal file).

"Title 1","Title 2","Title 3"
1,"prima riga
seconda riga",08/18/07
$ python csv_reader.py testlinebreak.csv
['Title 1', 'Title 2', 'Title 3']
['1', 'prima riga\nseconda riga', '08/18/07']

Scrittura

Quando si hanno dei dati da importare in una qualche altra applicazione, scrivere file CSV è altrettanto facile quanto leggerli. Si usa la funzione writer() per creare un oggetto writer per la scrittura. Per ogni riga si usa writerow() per scriverla nel file.

import csv
import sys

f = open(sys.argv[1], 'wt')
try:
    writer = csv.writer(f)
    writer.writerow( ('Title 1', 'Title 2', 'Title 3') )
    for i in range(10):
        writer.writerow( (i+1, chr(ord('a') + i), '08/%02d/07' % (i+1)) )
finally:
    f.close()

print open(sys.argv[1], 'rt').read()

L'output non sembra esattamente uguale ai dati esportati usati nell'esempio di lettura

$ python csv_writer.py testout.csv
Title 1,Title 2,Title 3
1,a,08/01/07
2,b,08/02/07
3,c,08/03/07
4,d,08/04/07
5,e,08/05/07
6,f,08/06/07
7,g,08/07/07
8,h,08/08/07
9,i,08/09/07
10,j,08/10/07

Il comportamento predefinito per racchiudere i dati tra virgolette (quoting) è diverso per la scrittura, quindi le colonne stringa non sono racchiuse tra virgolette. E' facile modificarlo aggiungendo un parametro di quoting per racchiudere tra virgolette i valori non numerici:

writer = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC)

Adesso le stringhe sono racchiuse tra virgolette:

$ python csv_writer_quoted.py testout_quoted.csv
"Title 1","Title 2","Title 3"
1,"a","08/01/07"
2,"b","08/02/07"
3,"c","08/03/07"
4,"d","08/04/07"
5,"e","08/05/07"
6,"f","08/06/07"
7,"g","08/07/07"
8,"h","08/08/07"
9,"i","08/09/07"
10,"j","08/10/07"

Quoting (racchiudere tra virgolette)

Ci sono quattro diverse opzioni di quoting, definite come costanti nel modulo csv. QUOTE_ALL Racchiude tutto tra virgolette, a prescindere dal tipo. QUOTE_MINIMAL Racchiude tra virgolette i campi con caratteri speciali (qualsiasi cosa che potrebbe confondere l'analizzatore configurato con lo stesso dialetto ed opzioni). Questa è l'opzione di quoting predefinita QUOTE_NONNUMERIC Racchiude tra virgolette tutti i campi che non sono interi o float. Quando viene usato in lettura, i campi in input che non sono racchiusi tra virgolette vengono convertiti in float. QUOTE_NONE Non racchiude nulla tra virgolette in scrittura. Quando usato in lettura, i caratteri "virgolette" vengono inclusi nei valori di campo (in genere sono invece trattati come delimitatori ed eliminati).

Dialetti

Ci sono molti parametri per controllare come il modulo csv analizza o scrive i dati. Piuttosto che passare ognuno di questi parametri al lettore ed allo scrittore separatamente, essi sono raggruppati convenientemente in un oggetto "dialetto" (dialect). Le classi dialetto possono essere registrate per nome, quindi i chiamanti del modulo csv non hanno bisogno di conoscere in anticipo le impostazioni dei parametri. La libreria standard include due dialetti: excel ed excel-tabs. Il dialetto excel è per lavorare con i dati nel formato di esportazione predefinito di Microsoft Excel, e funziona anche con OpenOffice o NeoOffice.

Si supponga che, invece di usare le virgole, il file di input usi | per delimitare i campi, tipo questo:

"Title 1"|"Title 2"|"Title 3"
1|"prima riga
seconda riga"|08/18/07

Un nuovo dialetto potrebbe essere registrato usando il delimitatore appropriato:

import csv

csv.register_dialect('pipes', delimiter='|')

with open('testdata.pipes', 'r') as f:
    reader = csv.reader(f, dialect='pipes')
    for row in reader:
        print row

ed il file può essere letto proprio come il file delimitato da virgole:

$ python csv_dialect.py
['Title 1', 'Title 2', 'Title 3']
['1', 'prima riga\nseconda riga', '08/18/07']

Per dettagli sui parametri del dialetto e come sono usati, fare riferimento alla documentazione della libreria standard per il modulo csv.

DictReader e DictWriter

Oltre a lavorare con sequenze di dati, il modulo csv include classi per lavorare con righe come dizionari. Le classi DictReader e DictWriter trascodificano le righe in dizionari. Le chiavi per il dizionario possono essere passate oppure ricavate per inferenza dalla prima riga dell'input (quando la riga contiene le intestazioni di colonna).

import csv
import sys

f = open(sys.argv[1], 'rt')
try:
    reader = csv.DictReader(f)
    for row in reader:
        print row
finally:
    f.close()

Il lettore e lo scrittore basati sul dizionario sono implementati come wrapper attorno alle classi corrispondenti basate sui dati in sequenza, ed usano gli stessi parametri ed API. L'unica differenza è che le righe sono dizionari invece che liste di tuple.

$ python csv_dictreader.py testdata.csv
{'Title 1': '1', 'Title 3': '08/18/07', 'Title 2': 'a'}
{'Title 1': '2', 'Title 3': '08/19/07', 'Title 2': 'b'}
{'Title 1': '3', 'Title 3': '08/20/07', 'Title 2': 'c'}
{'Title 1': '4', 'Title 3': '08/21/07', 'Title 2': 'd'}
{'Title 1': '5', 'Title 3': '08/22/07', 'Title 2': 'e'}
{'Title 1': '6', 'Title 3': '08/23/07', 'Title 2': 'f'}
{'Title 1': '7', 'Title 3': '08/24/07', 'Title 2': 'g'}
{'Title 1': '8', 'Title 3': '08/25/07', 'Title 2': 'h'}
{'Title 1': '9', 'Title 3': '08/26/07', 'Title 2': 'i'}

Si devono passare a DictWriter un elenco di nomi di campo così che possa conoscere in che modo le colonne debbano essere ordinate nella scrittura del file.

import csv
import sys

f = open(sys.argv[1], 'wt')
try:
    fieldnames = ('Title 1', 'Title 2', 'Title 3')
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    headers = dict( (n,n) for n in fieldnames )
    writer.writerow(headers)
    for i in range(10):
        writer.writerow({ 'Title 1':i+1,
                          'Title 2':chr(ord('a') + i),
                          'Title 3':'08/%02d/07' % (i+1),
                          })
finally:
    f.close()

print open(sys.argv[1], 'rt').read()
$ python csv_dictwriter.py testout.csv
Title 1,Title 2,Title 3
1,a,08/01/07
2,b,08/02/07
3,c,08/03/07
4,d,08/04/07
5,e,08/05/07
6,f,08/06/07
7,g,08/07/07
8,h,08/08/07
9,i,08/09/07
10,j,08/10/07

Vedere anche:

csv
La documentazione della libreria standard per questo modulo.
PEP 305
L'API per i file CSV
Persistenza e scambio dati