web-dev-qa-db-fra.com

CSV dans Python ajout d'un retour chariot supplémentaire sous Windows

Dans Python 2.7 sous Windows XP pro:

import csv
outfile = file('test.csv', 'w')
writer = csv.writer(outfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
writer.writerow(['hi','dude'])
writer.writerow(['hi2','dude2'])
outfile.close()

Il génère un fichier, test.csv, avec un\r supplémentaire à chaque ligne, comme suit:

test.csv

hi,dude\r\r\nhi2,dude2\r\r\n

au lieu de l'attendu:

hi,dude\r\nhi2,dude2\r\n

Pourquoi cela se produit-il ou s'agit-il vraiment du comportement souhaité?

194
apalopohapa

Sous Windows, ouvrez toujours vos fichiers en mode binaire ("rb" ou "wb") avant de les transmettre à csv.reader ou à csv.writer.

Bien que le fichier soit un fichier texte, CSV est considéré comme un format binaire par les bibliothèques concernées, avec "\ r\n" séparant les enregistrements. Si ce séparateur est écrit en mode texte, le runtime Python remplace le "\ n" par "\ r\n", d'où le "\ r\r\n" que vous avez observé dans votre fichier.

Voir cette réponse précédente .


Cette réponse a été publiée en 2010 et ne résout pas le problème en Python3.

L'une des corrections possibles dans Python3, comme décrit dans la réponse de @ YiboYang, ouvre le fichier avec le paramètre newline défini comme une chaîne vide:

f = open(path_to_file, 'w', newline='')
writer = csv.writer(f)
...
...
255
John Machin

Bien que @ john-machin donne une bonne réponse, ce n'est pas toujours la meilleure approche. Par exemple, cela ne fonctionne pas sur Python 3 à moins que vous ne codiez toutes vos entrées dans l'enregistreur CSV. En outre, le problème n'est pas résolu si le script souhaite utiliser sys.stdout en tant que flux.

Je suggère plutôt de définir l'attribut 'lineterminator' lors de la création du rédacteur:

import csv
import sys

doc = csv.writer(sys.stdout, lineterminator='\n')
doc.writerow('abc')
doc.writerow(range(3))

Cet exemple fonctionnera sur Python 2 et Python 3 et ne produira pas les caractères de nouvelle ligne indésirables. Notez toutefois que cela peut produire des sauts de ligne indésirables (en omettant le caractère LF sur les systèmes d'exploitation Unix).

Cependant, dans la plupart des cas, j'estime qu'un comportement est préférable et plus naturel que de traiter tous les fichiers CSV comme un format binaire. Je fournis cette réponse comme une alternative à votre considération.

227
Jason R. Coombs

Dans Python 3 (je n'ai pas essayé cela dans Python 2), vous pouvez aussi simplement faire

with open('output.csv','w',newline='') as f:
    writer=csv.writer(f)
    writer.writerow(mystuff)
    ...

selon documentation .

Plus à ce sujet dans la doc note de bas de page :

Si newline = '' n'est pas spécifié, les nouvelles lignes incorporées dans les champs entre guillemets ne seront pas interprétées correctement et sur les plates-formes qui utilisent\r\n les modifications à l'écriture, un\r supplémentaire sera ajouté. Il est toujours prudent de spécifier newline = '', car le module csv gère lui-même sa nouvelle ligne (universelle).

50
Yibo Yang

Je ne sais pas exactement pourquoi cela se produit, mais changer votre mode de fichier de "w" à "wb" le corrige. Voir ma réponse à " comment supprimer ^ M " pour plus de détails.

4
Ned Batchelder

Vous devez ajouter l'attribut newline = "\ n" pour ouvrir une fonction comme ceci:

with open('file.csv','w',newline="\n") as out:
    csv_out = csv.writer(out, delimiter =';')
3
Gregor Ažbe

Notez que si vous utilisez DictWriter, vous aurez une nouvelle ligne de la fonction open et une nouvelle ligne de la fonction writerow. Vous pouvez utiliser newline = '' dans la fonction open pour supprimer le newline supplémentaire.

2
Erick Stone

Vous pouvez introduire le paramètre lineterminator = '\ n' dans la commande csv writer.

import csv
delimiter='\t'
with open('tmp.csv', '+w', encoding='utf-8') as stream:
    writer = csv.writer(stream, delimiter=delimiter, quoting=csv.QUOTE_NONE, quotechar='',  lineterminator='\n')
    writer.writerow(['A1' , 'B1', 'C1'])
    writer.writerow(['A2' , 'B2', 'C2'])
    writer.writerow(['A3' , 'B3', 'C3'])
1
Wesam Na