CSV w Pythonie dodaje dodatkowy znak powrotu karetki w systemie Windows

231
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()

Generuje plik, test.csvz dodatkowym \rw każdym wierszu, tak:

test.csv

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

zamiast oczekiwanego:

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

Dlaczego tak się dzieje, czy jest to pożądane zachowanie?

Uwaga:

  • Takie zachowanie może wystąpić w Pythonie 2 lub 3.
apalopohapa
źródło
Prawdopodobnie duplikat programu piszącego CSV
John Y,

Odpowiedzi:

311

Python 3:

  • Zgodnie z opisem YiboYanga , ustawnewline=''
with open('output.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    ...
  • Jak zauważono w komentarzach CoDEmanX , ustawnewline='\n'
with open('output.csv', 'w', newline='\n', encoding='utf-8') as f:
    writer = csv.writer(f)
    ...

Python 2:

W systemie Windows zawsze otwieraj pliki w trybie binarnym ( "rb"lub "wb") przed przekazaniem ich do csv.readerlub csv.writer.

Mimo że plik jest plikiem tekstowym, zaangażowane biblioteki uznają format binarny za \r\noddzielny. Jeśli to separator jest napisane w trybie tekstowym, środowisko wykonawcze Python zastępuje \nsię \r\n, stąd \r\r\nobserwowane w pliku.

Zobacz poprzednią odpowiedź .

John Machin
źródło
3
Jest to w porządku dla ASCII, ale zabija kodowanie jak UTF-8. Poniższe rozwiązanie Jasona zadziałało dla mnie.
Tom
66
W Pythonie 3, udało mi się go naprawić za pomocą następujących opcji dla obiektu pliku: open(..., "w", newline="\n", encoding="utf-8"). newlinemoże być również pustym ciągiem, tym samym wynikiem. "wb"nie działa w Pythonie 3, łańcuchy i interfejs bufora są niekompatybilne.
CodeManX
Elegancki sposób obsługi dodatkowego zwrotu karetki
ForeverLearner
2
Nie działa w Python2, więc jeśli chcesz być zgodny zarówno z 2, jak i 3, skorzystaj z odpowiedzi udzielonej przez @ jason-r-coombs:writer = csv.writer(f, lineterminator='\n')
yossiz74
4
To wielka szkoda, że ​​taki podstawowy, powszechny i ​​prosty interfejs API nie działa zgodnie z wymaganiami
SomethingSomething
248

Chociaż @ john-machin daje dobrą odpowiedź, nie zawsze jest to najlepsze podejście. Na przykład nie działa w Pythonie 3, chyba że kodujesz wszystkie dane wejściowe do programu piszącego CSV. Ponadto nie rozwiązuje problemu, jeśli skrypt chce użyć sys.stdout jako strumienia.

Zamiast tego sugeruję ustawienie atrybutu „lineterminator” podczas tworzenia programu piszącego:

import csv
import sys

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

Ten przykład będzie działał na Python 2 i Python 3 i nie będzie generował niepożądanych znaków nowej linii. Należy jednak pamiętać, że może powodować niepożądane znaki nowej linii (pomijając znak LF w systemach operacyjnych Unix).

Jednak w większości przypadków uważam, że zachowanie jest lepsze i bardziej naturalne niż traktowanie całego pliku CSV jako formatu binarnego. Podaję tę odpowiedź jako alternatywę do rozważenia.

Jason R. Coombs
źródło
6
To jest najlepsza odpowiedź moim zdaniem. Jeśli chodzi o problem w Uniksie, co powiesz na wywołanie sys.platform i radzenie sobie z tym dynamicznie?
sovemp,
4
Moim zdaniem najlepsza odpowiedź, a lineterminator = '\ n' działa pięknie.
eikonal
1
Czy możesz podać przykład problemu, który powstaje, jeśli nie „zakodujesz wszystkich danych wejściowych do programu piszącego CSV”?
Stephen
UWAGA: korzystanie z tych środków \rnie jest już możliwe! Wygląda na to, że jest to błąd csvwriter, ale w tej chwili wyświetlanie niezgodnego CSV oznacza, że nie jest to właściwa droga.
flow2k
To rozwiązało ^Mproblem, podczas gdy 2 propozycje zaakceptowanej odpowiedzi nie zadziałały.
user985366
55

W Python 3 (nie próbowałem tego w Python 2), możesz po prostu to zrobić

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

zgodnie z dokumentacją .

Więcej na ten temat w przypisie doktora :

Jeśli nie podano newline = '', nowe wiersze osadzone w polach cytowanych nie będą poprawnie interpretowane, a na platformach, które używają \ r \ n podszewek przy pisaniu, zostaną dodane dodatkowe \ r. Zawsze powinno być bezpiecznie określić newline = '', ponieważ moduł csv ma ​​własną (uniwersalną) obsługę nowej linii.

Yibo Yang
źródło
2
@ Yibo-Yang, zaoszczędziłeś mi dużo czasu.
1man
4
ŚWIETNY. Potwierdziłem to w Pythonie 3.5
jef
Dlaczego nie byłoby to zachowanie domyślne?
Marc Stober
6

Możesz wprowadzić parametr lineterminator = '\ n' w poleceniu piszącym csv.

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'])
Wesam Na
źródło
1
W przypadku Python 3.5.2 była to jedyna rzecz, która działała dla mnie (cóż, użyłem właśnie lineterminator='\n'); moduł CSV wydawał się być początkiem \r\n. Brak zestawu argumentów, które openmiałyby jakikolwiek skutek.
Tommy
5

Nie jestem pewien, dlaczego tak się dzieje, ale zmiana trybu pliku z „w” na „wb” naprawia to. Zobacz moją odpowiedź na „ jak usunąć ^ M ”, aby uzyskać więcej informacji.

Ned Batchelder
źródło
3

Musisz dodać atrybut newline = "\ n", aby otworzyć funkcję w następujący sposób:

with open('file.csv','w',newline="\n") as out:
    csv_out = csv.writer(out, delimiter =';')
Gregor Ažbe
źródło
2

Zauważ, że jeśli użyjesz DictWriter, będziesz mieć nowy wiersz z funkcji open i nowy wiersz z funkcji writerow. Możesz użyć nowej linii = '' w ramach funkcji otwartej, aby usunąć dodatkową nową linię.

Erick Stone
źródło