Mit Python geschriebene CSV-Dateien enthalten Leerzeilen zwischen den einzelnen Zeilen

446
import csv

with open('thefile.csv', 'rb') as f:
  data = list(csv.reader(f))
  import collections
  counter = collections.defaultdict(int)

  for row in data:
        counter[row[10]] += 1


with open('/pythonwork/thefile_subset11.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    for row in data:
        if counter[row[10]] >= 504:
           writer.writerow(row)

Dieser Code liest thefile.csv, nimmt Änderungen vor und schreibt Ergebnisse in thefile_subset1.

Wenn ich jedoch die resultierende CSV in Microsoft Excel öffne, wird nach jedem Datensatz eine zusätzliche Leerzeile angezeigt!

Gibt es eine Möglichkeit, keine zusätzliche Leerzeile einzufügen?

l - '' '' '-' '' '' '' '' '' '' '
quelle
4
Bitte bestätigen Sie, dass dies passiert, wenn Sie diesen Code unter Windows
John Machin
Siehe die Antwort auf diesen Thread: stackoverflow.com/questions/3348460/…
Febin Mathew

Antworten:

886

Öffnen Sie in Python 2 den outfileModus 'wb'anstelle von 'w'. Das csv.writerschreibt \r\ndirekt in die Datei. Wenn Sie die Datei nicht in öffnen binären Modus, wird es schreiben , \r\r\nweil auf Windows Text - Modus wird jedes übersetzen \nin \r\n.

In Python 3 wurde die erforderliche Syntax geändert (siehe Dokumentationslinks unten). Öffnen Sie sie stattdessen outfilemit dem zusätzlichen Parameter newline=''(leere Zeichenfolge).

Beispiele:

# Python 2
with open('/pythonwork/thefile_subset11.csv', 'wb') as outfile:
    writer = csv.writer(outfile)

# Python 3
with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:
    writer = csv.writer(outfile)

Dokumentationslinks

Mark Tolonen
quelle
1
Wie auch immer, die Antwort von @Mark Tolonen löste viele Fragen im Zusammenhang mit den zusätzlichen Zeilen, die beim Speichern einer Standardtextdatei (keine CSV verwendet) hinzugefügt wurden.
Dlewin
1
Aus Gründen der Kompatibilität zwischen 2.6 / 2.7 und 3 können Sie io.opendas newlinesArgument verwenden. Wenn Sie immer noch in 2.x schreiben, scheint dies ohnehin eine bessere Wahl zu sein, da es vorwärtskompatibel ist.
jpmc26
@ jpmc26 Normalerweise ist das ein guter Rat, aber das CSV-Modul funktioniert nicht richtig mit io.open. Es gibt ein unicodecsvDrittanbieter-Modul für Python 2.7, das besser funktioniert.
Mark Tolonen
Irgendeine Idee, warum der newline=''Trick in Python3 mit StringIO oder TemporaryFile nicht funktioniert?
fmoo
@fmoo definieren "funktioniert nicht". Beide arbeiten so, wie ich es erwartet habe. StringIOpuffert die gleichen Codepunkte, die in eine Datei codiert würden, und TemporaryFileunterstützt den newlineParameter, sodass er wie bei geöffnet werden kann open. Stellen Sie eine Frage mit einem Beispielprogramm, das nicht funktioniert.
Mark Tolonen
65

Das Öffnen der Datei im Binärmodus "wb" funktioniert in Python 3+ nicht. Oder besser gesagt, Sie müssten Ihre Daten vor dem Schreiben in Binärdaten konvertieren. Das ist nur ein Ärger.

Stattdessen sollten Sie den Textmodus beibehalten, die neue Zeile jedoch als leer überschreiben. Wie so:

with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:
David Maddox
quelle
13

Die einfache Antwort ist, dass CSV-Dateien immer im Binärmodus geöffnet werden sollten, egal ob für die Eingabe oder Ausgabe, da sonst unter Windows Probleme mit dem Zeilenende auftreten. Speziell bei der Ausgabe wird das CSV - Modul schreiben \r\n(den Standardzeilenabschluss CSV) und dann (im Textmodus) die Laufzeit ersetzt die \ndurch \r\n(die Windows - Standard Line Terminator) gibt ein Ergebnis \r\r\n.

Mit dem herumzuspielen lineterminatorist NICHT die Lösung.

John Machin
quelle
Was ist dieser CSV "Standard", von dem Sie sprechen?
Dan Breslau
3
@ Dan: Ich habe "Standard" als Adjektiv verwendet, nicht als Substantiv, was "üblich" oder "alltäglich" bedeutet. Wenn Sie eine Annäherung an einen (Substantiv-) Standard wünschen
John Machin
1
Punkt ist (wie Sie implizieren), dass es keinen Standard gibt. Diese RFE ist informativ. Während \ r \ n unter Windows möglicherweise "Standard" ist, sehe ich Unix-Anwendungen dies normalerweise nicht so.
Dan Breslau
2
@ Dan: Das ist richtig - es gibt keinen Standard. Skripte sollten den gewünschten Lineterminator [sollte ROWterminator heißen] angeben (falls nicht der Standard) und weiterhin den Binärmodus verwenden, falls das Skript unter Windows ausgeführt wird, da sonst der "Lineterminator" möglicherweise überfüllt ist.
John Machin
8

Hinweis: Dies scheint nicht die bevorzugte Lösung zu sein, da die zusätzliche Zeile auf einem Windows-System hinzugefügt wurde. Wie im Python-Dokument angegeben :

Wenn csvfile ein Dateiobjekt ist, muss es auf Plattformen, auf denen dies einen Unterschied macht, mit dem Flag 'b' geöffnet werden.

Windows ist eine solche Plattform, auf der dies einen Unterschied macht. Während das Ändern des Zeilenabschlusses, wie unten beschrieben, das Problem möglicherweise behoben hat, kann das Problem insgesamt vermieden werden, indem die Datei im Binärmodus geöffnet wird. Man könnte sagen, diese Lösung ist "eleganter". Das "Fummeln" mit dem Zeilenabschluss hätte in diesem Fall wahrscheinlich zu nicht portierbarem Code zwischen Systemen geführt, wobei das Öffnen einer Datei im Binärmodus auf einem Unix-System keine Auswirkungen hat. dh. Dies führt zu systemübergreifendem Code.

Aus Python-Dokumenten :

Unter Windows öffnet 'b', das an den Modus angehängt ist, die Datei im Binärmodus, daher gibt es auch Modi wie 'rb', 'wb' und 'r + b'. Python unter Windows unterscheidet zwischen Text- und Binärdateien. Die Zeilenendezeichen in Textdateien werden beim Lesen oder Schreiben von Daten automatisch geringfügig geändert. Diese Änderung der Dateidaten hinter den Kulissen ist für ASCII-Textdateien in Ordnung, beschädigt jedoch Binärdaten wie JPEG- oder EXE-Dateien. Achten Sie beim Lesen und Schreiben solcher Dateien sehr darauf, den Binärmodus zu verwenden. Unter Unix schadet es nicht, ein 'b' an den Modus anzuhängen, sodass Sie es plattformunabhängig für alle Binärdateien verwenden können.

Original :

Als Teil der optionalen Parameter für den csv.writer müssen Sie möglicherweise den Liniensterminator ändern, wenn Sie zusätzliche Leerzeilen erhalten (Informationen hier ). Beispiel unten aus der Python-Seite CSV-Dokumente angepasst . Ändern Sie es von '\ n' in das, was es sein sollte. Da dies nur ein Stich in die Dunkelheit bei dem Problem ist, kann dies funktionieren oder auch nicht, aber es ist meine beste Vermutung.

>>> import csv
>>> spamWriter = csv.writer(open('eggs.csv', 'w'), lineterminator='\n')
>>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])
>>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
Derek Litz
quelle
Ich wollte gerade darüber posten - lineterminator = '\ n' hat in einem einfachen Test für mich funktioniert.
Dan Breslau
kann ich das machen> ?? mit open ('/ pythonwork / thefile_subset11.csv', 'w'), lineterminator = '\ n' als outfile:
l --'''''--------- '' '' ' '' '' ''
1
@I__: Sie sollten wirklich anfangen, die Python-Dokumente zu lesen. Derek gab Ihnen den Link: docs.python.org/library/csv.html
Dan Breslau
5

Ich schreibe diese Antwort für Python 3, da ich anfangs das gleiche Problem habe.

Ich sollte Daten von Arduino mit bekommen PySerialund sie in eine CSV-Datei schreiben. Jede Lesung in meinem Fall endete mit'\r\n' , sodass die neue Zeile immer jede Zeile trennte.

In meinem Fall hat die newline=''Option nicht funktioniert. Weil es einige Fehler zeigte wie:

with open('op.csv', 'a',newline=' ') as csv_file:

ValueError: illegal newline value: ''

Es schien also, dass sie hier das Auslassen von Zeilenumbrüchen nicht akzeptieren.

Als ich hier nur eine der Antworten sah, erwähnte ich den Zeilenabschluss im Writer-Objekt, wie z.

writer = csv.writer(csv_file, delimiter=' ',lineterminator='\r')

und das hat bei mir funktioniert, weil ich die zusätzlichen Zeilenumbrüche übersprungen habe.

Debanjan Dey
quelle
2
Das ist falsch. with open('my_file.csv', 'a',newline='') as csvfile: funktioniert absolut gut. Das Problem mit Ihrer Antwort ist, dass Sie hier schreiben ' 'anstatt''
Nasrin
2
with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

Der "lineterminator = '\ r'" erlaubt die Übergabe an die nächste Zeile ohne leere Zeile zwischen zwei.

SheRa
quelle
1

Ausgehend von dieser Antwort scheint es die sauberste Lösung zu sein, sie zu verwenden io.TextIOWrapper. Ich habe es geschafft, dieses Problem wie folgt für mich zu lösen:

from io import TextIOWrapper

...

with open(filename, 'wb') as csvfile, TextIOWrapper(csvfile, encoding='utf-8', newline='') as wrapper:
    csvwriter = csv.writer(wrapper)
    for data_row in data:
        csvwriter.writerow(data_row)

Die obige Antwort ist nicht mit Python 2 kompatibel. Um Kompatibilität zu haben, müsste man wohl einfach die gesamte Schreiblogik in einen ifBlock packen:

if sys.version_info < (3,):
    # Python 2 way of handling CSVs
else:
    # The above logic
Phantom-99w
quelle
0

Verwenden Sie die unten definierte Methode, um Daten in die CSV-Datei zu schreiben.

open('outputFile.csv', 'a',newline='')

Fügen Sie einfach einen zusätzlichen newline=''Parameter in die openMethode ein:

def writePhoneSpecsToCSV():
    rowData=["field1", "field2"]
    with open('outputFile.csv', 'a',newline='') as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(rowData)

Dadurch werden CSV-Zeilen geschrieben, ohne dass zusätzliche Zeilen erstellt werden!

Febin Mathew
quelle
-1

Bei Verwendung von Python 3 können Leerzeilen mithilfe des Codecs- Moduls vermieden werden. Wie in der Dokumentation angegeben, werden Dateien im Binärmodus geöffnet, sodass keine Änderung des Zeilenumbruchs erforderlich ist. Ich bin kürzlich auf dasselbe Problem gestoßen, und das hat bei mir funktioniert:

with codecs.open( csv_file,  mode='w', encoding='utf-8') as out_csv:
     csv_out_file = csv.DictWriter(out_csv)
JBa
quelle