Errore CSV Python: la riga contiene byte NULL


102

Sto lavorando con alcuni file CSV, con il seguente codice:

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

E un file sta generando questo errore:

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

Cosa posso fare? Google sembra suggerire che potrebbe essere un file Excel salvato in modo improprio come .csv. C'è un modo per aggirare questo problema in Python?

== AGGIORNAMENTO ==

Seguendo il commento di @ JohnMachin di seguito, ho provato ad aggiungere queste righe al mio script:

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')

E questo è l'output che ho ottenuto:

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

Quindi il file contiene effettivamente byte NUL.


Come si od -cdice che sia la prima riga?
Ignacio Vazquez-Abrams

quale query dovrei eseguire, qualcosa come cat my.csv | od -c | Di Più ? con quello ottengo: 0000000 D epartment F amil
AP257

Come viene generato il CSV? Da Excel, potresti provare un dialetto. In caso contrario, guardare diciamo: stackoverflow.com/questions/2753022/...
dr jimbob

Grazie. Non è il mio CSV e sfortunatamente non ho il potere di cambiarlo. Penso che sia stato creato come Excel e salvato come CSV (boo). Un dialetto sembra una buona idea - ci proverò!
AP257

Se è stato effettivamente salvato come CSV, dovrebbe funzionare. Una cosa che a volte trovo sono i file TSV (separati da tabulazioni) mascherati da CSV, quindi potresti provare a impostare un delimitatore di "\ t". Se è stato salvato come file Excel e l'estensione è stata modificata in CSV, nessun dialetto funzionerà. Penso che la tua unica opzione in tal caso sarebbe quella di utilizzare Excel per salvare le copie come CSV appropriato.
Thomas K

Risposte:


104

Come dice @ S.Lott, dovresti aprire i tuoi file in modalità "rb", non in modalità "rU". Tuttavia, questo potrebbe NON essere la causa del problema attuale. Per quanto ne so, l'utilizzo della modalità 'rU' ti rovinerebbe se sono incorporati \rnei dati, ma non causerebbe altri drammi. Noto anche che hai diversi file (tutti aperti con 'rU' ??) ma solo uno che causa un problema.

Se il modulo csv dice che hai un byte "NULL" (messaggio stupido, dovrebbe essere "NUL") nel tuo file, allora devi controllare cosa c'è nel tuo file. Suggerirei di farlo anche se l'uso di "rb" risolve il problema.

repr()è (o vuole essere) il tuo amico di debug. Mostrerà in modo inequivocabile quello che hai, in un modo indipendente dalla piattaforma (che è utile per gli aiutanti che non sono consapevoli di ciò che odè o fa). Fai questo:

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

e copia / incolla con attenzione (non ridigitare) il risultato in una modifica della tua domanda (non in un commento).

Nota anche che se il file è davvero pericoloso, ad esempio no \ r o \ n entro una distanza ragionevole dall'inizio del file, il numero di riga riportato da reader.line_numsarà (inutilmente) 1. Trova dove si trova il primo \x00(se esiste) facendo

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

e assicurati di scaricare almeno quel numero di byte con repr o od.

Cosa data.count('\x00')ti dice? Se ce ne sono molti, potresti voler fare qualcosa di simile

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

in modo da poter vedere i byte NUL nel contesto.

Se puoi vedere \x00nell'output (o \0nel tuo od -coutput), allora hai sicuramente NUL byte nel file e dovrai fare qualcosa del genere:

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

A proposito, hai guardato il file (comprese le ultime righe) con un editor di testo? Sembra effettivamente un file CSV ragionevole come gli altri file (senza eccezione "NULL byte")?


Grazie mille per questo aiuto molto dettagliato. Ci sono molti \ x00 caratteri nel file (vedi modifica alla domanda) - è strano, perché in un editor di testo sembra un file CSV perfettamente ragionevole.
AP257

1
@ AP257: '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1è la "firma" che denota un file di documento composto OLE2, ad esempio un file .XLS di Excel 97-2003 . Trovo "in un editor di testo sembra un file CSV perfettamente ragionevole" per essere assolutamente incredibile . Devi aver guardato un file diverso, un file CSV valido, in un'altra cartella o su un'altra macchina o in un altro momento. Nota che il tuo odoutput non era da un file XLS.
John Machin

8
@ AP257: Qualche motivo particolare per cui non hai accettato questa risposta?
John Machin

Funziona, ma dovrebbe essere possibile e piacevole al volo con un oggetto simile a un file che filtra il CSV e può essere passato csv.readerdirettamente.
gerrit

1
Non dovrebbe fo.write(data.replace('\x00', ''))essere fo.write(data.replace(b'\x00', b''))? Python 3.6 qui ...
Boern

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

Questo funziona per me.


Risolto per il mio caso, i valori nulli erano i valori "\ 0". Grazie.
Joab Mendes

19

Leggerlo come UTF-16 è stato anche un mio problema.

Ecco il mio codice che ha finito per funzionare:

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

Dove location è la directory del tuo file csv.


13

Mi sono imbattuto anche in questo problema. Utilizzando il csvmodulo Python , stavo cercando di leggere un file XLS creato in MS Excel e NULL bytemi sono imbattuto nell'errore che stavi ricevendo. Mi sono guardato intorno e ho trovato il modulo xlrd Python per la lettura e la formattazione dei dati dai file del foglio di calcolo MS Excel. Con il xlrdmodulo, non solo sono in grado di leggere correttamente il file, ma posso anche accedere a molte parti diverse del file in un modo che prima non avrei potuto.

Ho pensato che potrebbe aiutarti.


7
Grazie per aver segnalato quel modulo. È interessante notare che sono andato a scaricarlo e ho notato che l'autore non era altro che @John_Machin, che è anche il commento principale su questa domanda.
Evan

11

La conversione della codifica del file sorgente da UTF-16 a UTF-8 risolve il mio problema.

Come convertire un file in utf-8 in Python?

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

Potresti semplicemente incorporare un generatore per filtrare i valori nulli se vuoi fingere che non esistano. Ovviamente questo presuppone che i byte nulli non facciano realmente parte della codifica e siano davvero una sorta di artefatto o bug errato.

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

Perché stai facendo questo?

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

I documenti sono abbastanza chiari che devi fare questo:

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

La modalità deve essere "rb" per leggere.

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

Se csvfile è un oggetto file, deve essere aperto con il flag "b" sulle piattaforme in cui questo fa la differenza.


@ AP257: "Non aiuta"? Significa che cosa? Eventuali messaggi di errore specifici?
S.Lott

1
@ S.Lott: Significa che ottiene la stessa risposta di prima. La realtà è che ha a che fare con un camaleonte o un file mutaforma ... quando lo scarica odo lo guarda in un editor di testo, sembra un file CSV perfettamente normale. Tuttavia, quando scarica i primi pochi byte con Python repr (), diventa come un file .XLS di Excel (che è stato rinominato per avere un'estensione CSV).
John Machin

@ John Machin: "un file .XLS Excel (che è stato rinominato per avere un'estensione CSV" Ha senso che non possa essere elaborato affatto.
S.Lott

1
@ S.Lott: Con quel contenuto, ha senso che il modulo csv non possa elaborarlo; tuttavia il modulo xlrd può elaborarlo. Sensibilmente, nessuno dei due moduli deduce nulla dal nome del file di input, se effettivamente l'input è un file con un nome.
John Machin

1
@ John Machin: "nessuno dei due moduli deduce nulla dal nome del file di input". Vero. Il mio framework applicativo dipende da questo fatto. Non crediamo che il nome del file significhi qualcosa, poiché le persone commettono errori ("bugie"). Quindi dobbiamo controllare un sacco di alternative finché non si fa clic.
S.Lott


2

Invece del lettore csv, uso il file di lettura e la funzione di divisione per la stringa:

lines = open(input_file,'rb') 

for line_all in lines:

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

1

Ho ricevuto lo stesso errore. Ho salvato il file in UTF-8 e ha funzionato.


1
Potresti aver ricevuto lo stesso messaggio di errore, ma la causa sarebbe stata diversa: probabilmente l'hai salvato originariamente come UTF-16 (ciò che il Blocco note chiama "Unicode").
John Machin

1

Questo è successo a me quando ho creato un file CSV con OpenOffice Calc. Non è successo quando ho creato il file CSV nel mio editor di testo, anche se in seguito l'ho modificato con Calc.

Ho risolto il mio problema copiando e incollando nel mio editor di testo i dati dal mio file creato da Calc a un nuovo file creato dall'editor.


1

Ho avuto lo stesso problema aprendo un CSV prodotto da un webservice che inseriva byte NULL in intestazioni vuote. Ho fatto quanto segue per pulire il file:

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...

Dichiarazione di non responsabilità: tieni presente che questo sovrascrive i tuoi dati originali. Assicurati di averne una copia di backup. Sei stato avvertito!


0

Per tutti coloro che odiano la modalità file "rU": ho appena provato ad aprire un file CSV da una macchina Windows su un Mac con la modalità file "rb" e ho ricevuto questo errore dal modulo csv:

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

L'apertura del file in modalità "rU" funziona correttamente. Adoro la modalità newline universale: mi fa risparmiare così tante seccature.


0

Ho riscontrato questo problema durante l'utilizzo di scrapy e il recupero di un file csv zippato senza avere un middleware corretto per decomprimere il corpo della risposta prima di passarlo al csvreader. Quindi il file non era realmente un file CSV e ha line contains NULL bytegenerato l' errore di conseguenza.


0

Hai provato a utilizzare gzip.open?

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

Stavo cercando di aprire un file che era stato compresso ma aveva l'estensione ".csv" invece di "csv.gz". Questo errore ha continuato a comparire fino a quando non ho usato gzip.open


-1

Un caso è questo: se il file CSV contiene righe vuote, potrebbe essere visualizzato questo errore. Controllare la riga è necessario prima di procedere con la scrittura o la lettura.

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

Ho risolto il mio problema aggiungendo questo segno di spunta nel codice.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.