Python CSV-Fehler: Zeile enthält NULL-Byte


102

Ich arbeite mit einigen CSV-Dateien mit dem folgenden Code:

reader = csv.reader(open(filepath, "rU"))
try:
    for row in reader:
        print 'Row read successfully!', row
except csv.Error, e:
    sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e))

Und eine Datei löst diesen Fehler aus:

file my.csv, line 1: line contains NULL byte

Was kann ich tun? Google scheint darauf hinzuweisen, dass es sich möglicherweise um eine Excel-Datei handelt, die nicht ordnungsgemäß als CSV-Datei gespeichert wurde. Gibt es eine Möglichkeit, dieses Problem in Python zu umgehen?

== UPDATE ==

Nach dem Kommentar von @ JohnMachin unten habe ich versucht, diese Zeilen zu meinem Skript hinzuzufügen:

print repr(open(filepath, 'rb').read(200)) # dump 1st 200 bytes of file
data = open(filepath, 'rb').read()
print data.find('\x00')
print data.count('\x00')

Und das ist die Ausgabe, die ich bekommen habe:

'\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1\x00\x00\x00\x00\x00\x00\x00\x00\ .... <snip>
8
13834

Die Datei enthält also tatsächlich NUL-Bytes.


Wie sieht od -cdie erste Zeile aus?
Ignacio Vazquez-Abrams

Welche Abfrage soll ich ausführen, so etwas wie cat my.csv | od -c | Mehr ? damit bekomme ich: 0000000 D epartment F amil
AP257

Wie wird die CSV generiert? Von Excel aus können Sie möglicherweise einen Dialekt ausprobieren. Ansonsten schauen Sie bitte
Dr. Jimbob

Vielen Dank. Es ist nicht meine CSV, und leider kann ich sie nicht ändern. Ich denke, es wurde als Excel erstellt und als CSV (boo) gespeichert. Ein Dialekt klingt nach einer guten Idee - das werde ich versuchen!
AP257

Wenn es tatsächlich als CSV gespeichert wurde, sollte es funktionieren. Eine Sache, die ich manchmal finde, sind TSV-Dateien (tabulatorgetrennte Dateien), die sich als CSV tarnen. Sie können also versuchen, ein Trennzeichen von '\ t' festzulegen. Wenn es als Excel-Datei gespeichert und die Erweiterung in CSV geändert wurde, funktioniert kein Dialekt. Ich denke, Ihre einzige Option in diesem Fall wäre, Excel zu verwenden, um Kopien als richtige CSV zu speichern.
Thomas K

Antworten:


104

Wie @ S.Lott sagt, sollten Sie Ihre Dateien im 'rb'-Modus und nicht im' rU'-Modus öffnen. Dies kann jedoch NICHT zu Ihrem aktuellen Problem führen. Soweit ich weiß, würde die Verwendung des 'rU'-Modus Sie durcheinander bringen, wenn \rin die Daten eingebettet sind , aber keine anderen Dramen verursachen. Ich stelle auch fest, dass Sie mehrere Dateien haben (alle mit 'rU' geöffnet?), Aber nur eine, die ein Problem verursacht.

Wenn das CSV-Modul angibt, dass Ihre Datei ein "NULL" -Byte (dumme Nachricht, sollte "NUL" sein) enthält, müssen Sie überprüfen, was sich in Ihrer Datei befindet. Ich würde vorschlagen, dass Sie dies auch dann tun, wenn die Verwendung von 'rb' das Problem beseitigt.

repr()ist (oder will) dein Debugging-Freund. Es wird auf plattformunabhängige Weise eindeutig zeigen, was Sie haben (was für Helfer hilfreich ist, die nicht wissen, was odist oder tut). Mach das:

print repr(open('my.csv', 'rb').read(200)) # dump 1st 200 bytes of file

und kopieren Sie das Ergebnis sorgfältig in eine Bearbeitung Ihrer Frage (nicht in einen Kommentar).

Beachten Sie auch, dass, wenn die Datei wirklich zwielichtig ist, z. B. no \ r oder \ n, in angemessener Entfernung vom Dateianfang, die von gemeldete Zeilennummer reader.line_num(nicht hilfreich) 1 \x00lautet. 1. Finden Sie, wo sich die erste befindet (falls vorhanden), indem Sie dies tun

data = open('my.csv', 'rb').read()
print data.find('\x00')

und stellen Sie sicher, dass Sie mindestens so viele Bytes mit repr oder od sichern.

Was data.count('\x00')sagt dir das? Wenn es viele gibt, möchten Sie vielleicht so etwas tun

for i, c in enumerate(data):
    if c == '\x00':
        print i, repr(data[i-30:i]) + ' *NUL* ' + repr(data[i+1:i+31])

damit Sie die NUL-Bytes im Kontext sehen können.

Wenn Sie \x00in der Ausgabe (oder \0in Ihrer od -cAusgabe) sehen können, haben Sie definitiv NUL-Bytes in der Datei, und Sie müssen Folgendes tun:

fi = open('my.csv', 'rb')
data = fi.read()
fi.close()
fo = open('mynew.csv', 'wb')
fo.write(data.replace('\x00', ''))
fo.close()

Haben Sie sich die Datei (einschließlich der letzten Zeilen) übrigens mit einem Texteditor angesehen? Sieht es tatsächlich aus wie eine vernünftige CSV-Datei wie die anderen (keine "NULL-Byte" -Ausnahme) Dateien?


Vielen Dank für diese sehr detaillierte Hilfe. Die Datei enthält viele \ x00 Zeichen (siehe Bearbeiten, um Fragen zu stellen) - es ist seltsam, weil es in einem Texteditor wie eine absolut vernünftige CSV-Datei aussieht.
AP257

1
@ AP257: '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1ist die "Signatur", die eine zusammengesetzte OLE2-Dokumentdatei bezeichnet - z. B. eine Excel 97-2003 .XLS-Datei . Ich finde "in einem Texteditor sieht es aus wie eine absolut vernünftige CSV-Datei" absolut unglaublich . Sie müssen eine andere Datei, eine gültige CSV-Datei, in einem anderen Ordner oder auf einem anderen Computer oder zu einem anderen Zeitpunkt angesehen haben. Beachten Sie, dass Ihre odAusgabe nicht aus einer XLS-Datei stammt.
John Machin

8
@ AP257: Gibt es einen bestimmten Grund, warum Sie diese Antwort nicht akzeptiert haben?
John Machin

Funktioniert, sollte aber im laufenden Betrieb mit einem dateiähnlichen Objekt möglich und nett sein, das die CSV filtert und csv.readerdirekt an übergeben werden kann.
Gerrit

1
Sollte nicht fo.write(data.replace('\x00', ''))sein fo.write(data.replace(b'\x00', b''))? Python 3.6 hier ...
Boern

23
data_initial = open("staff.csv", "rb")
data = csv.reader((line.replace('\0','') for line in data_initial), delimiter=",")

Das funktioniert bei mir.


Für meinen Fall gelöst, waren die Null die '\ 0'-Werte. Vielen Dank.
Joab Mendes

19

Es als UTF-16 zu lesen war auch mein Problem.

Hier ist mein Code, der funktioniert hat:

f=codecs.open(location,"rb","utf-16")
csvread=csv.reader(f,delimiter='\t')
csvread.next()
for row in csvread:
    print row

Wo Speicherort ist das Verzeichnis Ihrer CSV-Datei.


13

Ich bin auch auf dieses Problem gestoßen. Mit dem Python- csvModul habe ich versucht, eine in MS Excel erstellte XLS-Datei zu lesen und bin auf den NULL byteFehler gestoßen, den Sie erhalten haben. Ich sah mich um und fand das xlrd Python-Modul zum Lesen und Formatieren von Daten aus MS Excel-Tabellenkalkulationsdateien. Mit dem xlrdModul kann ich nicht nur die Datei richtig lesen, sondern auch auf viele verschiedene Teile der Datei zugreifen, wie ich es vorher nicht konnte.

Ich dachte, es könnte dir helfen.


7
Vielen Dank für den Hinweis auf dieses Modul. Interessanterweise habe ich es heruntergeladen und festgestellt, dass der Autor kein anderer als @John_Machin war, der auch der Top-Kommentar zu dieser Frage ist.
Evan

11

Das Konvertieren der Codierung der Quelldatei von UTF-16 nach UTF-8 löst mein Problem.

Wie konvertiere ich eine Datei in Python in utf-8?

import codecs
BLOCKSIZE = 1048576 # or some other, desired size in bytes
with codecs.open(sourceFileName, "r", "utf-16") as sourceFile:
    with codecs.open(targetFileName, "w", "utf-8") as targetFile:
        while True:
            contents = sourceFile.read(BLOCKSIZE)
            if not contents:
                break
            targetFile.write(contents)

7

Sie können einfach einen Generator einbinden, um die Nullwerte herauszufiltern, wenn Sie so tun möchten, als ob sie nicht existieren. Dies setzt natürlich voraus, dass die Null-Bytes nicht wirklich Teil der Codierung sind und wirklich eine Art fehlerhaftes Artefakt oder Fehler sind.

with open(filepath, "rb") as f:
    reader = csv.reader( (line.replace('\0','') for line in f) )

    try:
        for row in reader:
            print 'Row read successfully!', row
    except csv.Error, e:
        sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e))

2

Warum tust du das?

 reader = csv.reader(open(filepath, "rU"))

Die Dokumente sind ziemlich klar, dass Sie dies tun müssen:

with open(filepath, "rb") as src:
    reader= csv.reader( src )

Der Modus muss zum Lesen "rb" sein.

http://docs.python.org/library/csv.html#csv.reader

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


@ AP257: "Hilft nicht"? Bedeutet, was? Irgendwelche spezifischen Fehlermeldungen?
S.Lott

1
@ S.Lott: Bedeutet, er bekommt die gleiche Antwort wie zuvor. Die Realität ist, dass er es mit einer Chamäleon- oder Gestaltwandler-Datei zu tun hat ... Wenn er sie mit odeinem Texteditor ablegt oder in einem Texteditor betrachtet, sieht es aus wie eine ganz normale CSV-Datei. Wenn er jedoch die ersten Bytes mit Python repr () speichert, sieht es wie eine Excel-XLS-Datei aus (die in eine CSV-Erweiterung umbenannt wurde).
John Machin

@ John Machin: "Eine Excel .XLS-Datei (die in eine CSV-Erweiterung umbenannt wurde" Es macht Sinn, dass sie überhaupt nicht verarbeitet werden kann.
S.Lott

1
@ S.Lott: Bei diesem Inhalt ist es sinnvoll, dass das CSV-Modul ihn nicht verarbeiten kann. Das xlrd-Modul kann es jedoch verarbeiten. Sinnvollerweise leitet keines der Module etwas aus dem Namen der Eingabedatei ab, wenn es sich bei der Eingabe tatsächlich um eine Datei mit einem Namen handelt.
John Machin

1
@ John Machin: "Kein Modul leitet etwas aus dem Namen der Eingabedatei ab". Wahr. Mein Anwendungsrahmen hängt von dieser Tatsache ab. Wir vertrauen nicht darauf, dass der Dateiname etwas bedeutet, da die Leute Fehler machen ("Lüge"). Wir müssen also eine Reihe von Alternativen prüfen, bis man klickt.
S.Lott

2

Anscheinend handelt es sich um eine XLS-Datei und nicht um eine CSV-Datei, wie http://www.garykessler.net/library/file_sigs.html bestätigt


Nicht unbedingt, aber ja, das könnte eine Ursache sein. Ich habe diesen Fehler erhalten, als ich versucht habe, eine CSV-Datei zu analysieren, die von Excel aus einer XLSX-Datei gespeichert wurde.
Cerin

Mit dieser magischen Zahl ist es die Ursache, dass XLSX andere magische Zahlen hat
Xavier Combelle

2

Anstelle des CSV-Readers verwende ich die Funktion zum Lesen von Dateien und Teilen für Zeichenfolgen:

lines = open(input_file,'rb') 

for line_all in lines:

    line=line_all.replace('\x00', '').split(";")

1

Ich habe den gleichen Fehler bekommen. Die Datei wurde in UTF-8 gespeichert und es hat funktioniert.


1
Möglicherweise haben Sie dieselbe Fehlermeldung erhalten, aber die Ursache wäre anders gewesen - Sie haben sie wahrscheinlich ursprünglich als UTF-16 gespeichert (was Notepad "Unicode" nennt).
John Machin

1

Dies ist mir passiert, als ich mit OpenOffice Calc eine CSV-Datei erstellt habe. Es ist nicht passiert, als ich die CSV-Datei in meinem Texteditor erstellt habe, auch wenn ich sie später mit Calc bearbeitet habe.

Ich habe mein Problem gelöst, indem ich die Daten aus meiner von Calc erstellten Datei in eine vom Editor erstellte Datei in meinen Texteditor kopiert habe.


1

Ich hatte das gleiche Problem beim Öffnen einer CSV, die von einem Webservice erstellt wurde, der NULL-Bytes in leere Header einfügte. Ich habe Folgendes getan, um die Datei zu bereinigen:

with codecs.open ('my.csv', 'rb', 'utf-8') as myfile:
    data = myfile.read()
    # clean file first if dirty
    if data.count( '\x00' ):
        print 'Cleaning...'
        with codecs.open('my.csv.tmp', 'w', 'utf-8') as of:
            for line in data:
                of.write(line.replace('\x00', ''))

        shutil.move( 'my.csv.tmp', 'my.csv' )

with codecs.open ('my.csv', 'rb', 'utf-8') as myfile:
    myreader = csv.reader(myfile, delimiter=',')
    # Continue with your business logic here...

Haftungsausschluss: Beachten Sie, dass dadurch Ihre Originaldaten überschrieben werden. Stellen Sie sicher, dass Sie eine Sicherungskopie davon haben. Du wurdest gewarnt!


0

Für all diese 'rU'-Dateimodus-Hasser: Ich habe gerade versucht, eine CSV-Datei von einem Windows-Computer auf einem Mac mit dem' rb'-Dateimodus zu öffnen, und habe diesen Fehler vom CSV-Modul erhalten:

Error: new-line character seen in unquoted field - do you need to 
open the file in universal-newline mode?

Das Öffnen der Datei im 'rU'-Modus funktioniert einwandfrei. Ich liebe den Universal-Newline-Modus - er erspart mir so viel Ärger.


0

Ich bin darauf gestoßen, als ich Scrapy verwendet und eine komprimierte CSV-Datei abgerufen habe, ohne über eine korrekte Middleware zum Entpacken des Antwortkörpers zu verfügen, bevor er an den CSV-Reader übergeben wurde. Daher war die Datei nicht wirklich eine CSV-Datei und warf den line contains NULL byteFehler entsprechend.


0

Haben Sie versucht, gzip.open zu verwenden?

with gzip.open('my.csv', 'rb') as data_file:

Ich habe versucht, eine Datei zu öffnen, die komprimiert wurde, aber die Erweiterung '.csv' anstelle von 'csv.gz' hatte. Dieser Fehler trat immer wieder auf, bis ich gzip.open verwendete


-1

Ein Fall ist: - Wenn die CSV-Datei leere Zeilen enthält, kann dieser Fehler auftreten. Überprüfen Sie, ob eine Zeile erforderlich ist, bevor Sie mit dem Schreiben oder Lesen fortfahren.

for row in csvreader:
        if (row):       
            do something

Ich habe mein Problem gelöst, indem ich diese Prüfung in den Code eingefügt habe.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.