Supposons que j'ai un csv.DictReader
objet et je veux l'écrire sous forme de fichier CSV. Comment puis-je faire ceci?
Je sais que je peux écrire le lignes de données comme ceci:
dr = csv.DictReader(open(f), delimiter='\t')
# process my dr object
# ...
# write out object
output = csv.DictWriter(open(f2, 'w'), delimiter='\t')
for item in dr:
output.writerow(item)
Mais comment puis-je inclure les noms de champs?
Modifier:
Dans 2.7/3.2, il y a ne nouvelle méthode writeheader()
. En outre, la réponse de John Machin fournit une méthode plus simple pour écrire la ligne d'en-tête.
Exemple simple d'utilisation de la méthode writeheader()
maintenant disponible dans 2.7/3.2:
from collections import OrderedDict
ordered_fieldnames = OrderedDict([('field1',None),('field2',None)])
with open(outfile,'wb') as fou:
dw = csv.DictWriter(fou, delimiter='\t', fieldnames=ordered_fieldnames)
dw.writeheader()
# continue on to write data
L'instanciation de DictWriter nécessite un argument de noms de champs.
De la documentation :
Le paramètre fieldnames identifie l'ordre dans lequel les valeurs du dictionnaire transmises à la méthode writerow () sont écrites dans le fichier csv.
En d'autres termes: l'argument Fieldnames est requis car Python dicts sont par nature non ordonnés.
Voici un exemple d’écriture de l’en-tête et des données dans un fichier.
Remarque: la déclaration with
a été ajoutée dans la version 2.6. Si vous utilisez 2.5: from __future__ import with_statement
with open(infile,'rb') as fin:
dr = csv.DictReader(fin, delimiter='\t')
# dr.fieldnames contains values from first row of `f`.
with open(outfile,'wb') as fou:
dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames)
headers = {}
for n in dw.fieldnames:
headers[n] = n
dw.writerow(headers)
for row in dr:
dw.writerow(row)
Comme @FM le mentionne dans un commentaire, vous pouvez condenser l'écriture d'en-tête dans une ligne, par exemple:
with open(outfile,'wb') as fou:
dw = csv.DictWriter(fou, delimiter='\t', fieldnames=dr.fieldnames)
dw.writerow(dict((fn,fn) for fn in dr.fieldnames))
for row in dr:
dw.writerow(row)
Quelques options:
(1) Établissez laborieusement une dictée de mappage d’identité (c’est-à-dire à ne rien faire) à partir de vos noms de champs afin que csv.DictWriter puisse la reconvertir en liste et la transmettre à une instance de csv.writer.
(2) La documentation mentionne "l'instance writer
sous-jacente" ... donc utilisez-la (exemple à la fin).
dw.writer.writerow(dw.fieldnames)
(3) Évitez les frais généraux csv.Dictwriter et faites-le vous-même avec csv.writer
Écrire des données:
w.writerow([d[k] for k in fieldnames])
ou
w.writerow([d.get(k, restval) for k in fieldnames])
Au lieu de la extrasaction
"fonctionnalité", je préférerais la coder moi-même; De cette façon, vous pouvez signaler TOUS les "extras" avec les clés et les valeurs, pas seulement la première clé supplémentaire. Ce qui est vraiment gênant avec DictWriter, c’est que si vous avez vérifié les clés vous-même lors de la construction de chaque dict, vous devez vous rappeler d’utiliser extrasaction = 'ignore', sinon il LENT LENTEMENT (les noms de champs sont une liste), répétez le contrôle:
wrong_fields = [k for k in rowdict if k not in self.fieldnames]
============
>>> f = open('csvtest.csv', 'wb')
>>> import csv
>>> fns = 'foo bar zot'.split()
>>> dw = csv.DictWriter(f, fns, restval='Huh?')
# dw.writefieldnames(fns) -- no such animal
>>> dw.writerow(fns) # no such luck, it can't imagine what to do with a list
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\python26\lib\csv.py", line 144, in writerow
return self.writer.writerow(self._dict_to_list(rowdict))
File "C:\python26\lib\csv.py", line 141, in _dict_to_list
return [rowdict.get(key, self.restval) for key in self.fieldnames]
AttributeError: 'list' object has no attribute 'get'
>>> dir(dw)
['__doc__', '__init__', '__module__', '_dict_to_list', 'extrasaction', 'fieldnam
es', 'restval', 'writer', 'writerow', 'writerows']
# eureka
>>> dw.writer.writerow(dw.fieldnames)
>>> dw.writerow({'foo':'oof'})
>>> f.close()
>>> open('csvtest.csv', 'rb').read()
'foo,bar,zot\r\noof,Huh?,Huh?\r\n'
>>>
Une autre façon de faire est d’ajouter, avant d’ajouter des lignes dans votre sortie, la ligne suivante:
output.writerow(dict(Zip(dr.fieldnames, dr.fieldnames)))
Le zip renverrait une liste de doublet contenant la même valeur. Cette liste pourrait être utilisée pour créer un dictionnaire.