Error de Python CSV: la línea contiene un byte NULL

102

Estoy trabajando con algunos archivos CSV, con el siguiente código:

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

Y un archivo arroja este error:

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

¿Que puedo hacer? Google parece sugerir que puede ser un archivo de Excel que se guardó incorrectamente como .csv. ¿Hay alguna forma de solucionar este problema en Python?

== ACTUALIZAR ==

Siguiendo el comentario de @ JohnMachin a continuación, intenté agregar estas líneas a mi 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')

Y este es el resultado que obtuve:

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

Por tanto, el archivo contiene NUL bytes.

AP257
fuente
¿Cómo od -cdice que se ve la primera línea?
Ignacio Vazquez-Abrams
qué consulta debo ejecutar, algo como cat my.csv | od -c | más ? con eso obtengo: 0000000 D epartment F amil
AP257
¿Cómo se genera el CSV? Desde Excel, es posible que pueda probar un dialecto. De lo contrario, mire decir: stackoverflow.com/questions/2753022/…
dr jimbob
Gracias. No es mi CSV y, lamentablemente, no tengo el poder para cambiarlo. Creo que se creó como Excel y se guardó como CSV (boo). Un dialecto suena como una buena idea, ¡lo intentaré!
AP257
Si realmente se ha guardado como CSV, debería funcionar. Una cosa que a veces encuentro son archivos TSV (separados por tabulaciones) que se hacen pasar por CSV, por lo que podría intentar establecer un delimitador de '\ t'. Si se guardó como un archivo de Excel y la extensión cambió a CSV, ningún dialecto funcionará. Creo que su única opción en ese caso sería usar Excel para guardar copias como CSV adecuado.
Thomas K

Respuestas:

104

Como dice @ S.Lott, debería abrir sus archivos en modo 'rb', no en modo 'rU'. Sin embargo, es posible que eso NO esté causando su problema actual. Hasta donde yo sé, usar el modo 'rU' lo arruinaría si hubiera \rdatos incrustados , pero no causaría ningún otro drama. También noto que tiene varios archivos (todos abiertos con 'rU' ??) pero solo uno causa un problema.

Si el módulo csv dice que tiene un byte "NULL" (mensaje tonto, debería ser "NUL") en su archivo, entonces necesita verificar qué hay en su archivo. Le sugiero que haga esto incluso si el uso de 'rb' hace que el problema desaparezca.

repr()es (o quiere ser) su amigo de depuración. Mostrará sin ambigüedades lo que tienes, de manera independiente de la plataforma (lo cual es útil para los ayudantes que no saben qué odes o qué hace). Hacer esto:

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

y copie / pegue cuidadosamente (no vuelva a escribir) el resultado en una edición de su pregunta (no en un comentario).

También tenga en cuenta que si el archivo es realmente dudoso, por ejemplo, no \ r o \ n dentro de una distancia razonable desde el inicio del archivo, el número de línea informado por reader.line_numserá (inútilmente) 1. Busque dónde está el primero \x00(si lo hay) haciendo

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

y asegúrese de volcar al menos esa cantidad de bytes con repr u od.

¿Qué data.count('\x00')te dice? Si hay muchos, es posible que desee hacer algo como

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

para que pueda ver los bytes NUL en contexto.

Si puede ver \x00en la salida (o \0en su od -csalida), entonces definitivamente tiene byte (s) NUL en el archivo y deberá hacer algo como esto:

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

Por cierto, ¿ha mirado el archivo (incluidas las últimas líneas) con un editor de texto? ¿Realmente parece un archivo CSV razonable como los otros archivos (sin excepción de "bytes NULL")?

John Machin
fuente
Muchas gracias por esta ayuda tan detallada. Hay muchos caracteres \ x00 en el archivo (consulte editar a la pregunta); es extraño, porque en un editor de texto parece un archivo CSV perfectamente razonable.
AP257
1
@ AP257: '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1es la "firma" que indica un archivo de documento compuesto OLE2, por ejemplo, un archivo Excel 97-2003 .XLS . Encuentro que "en un editor de texto parece un archivo CSV perfectamente razonable" es absolutamente increíble . Debes haber estado mirando un archivo diferente, un archivo CSV válido, en otra carpeta o en otra máquina o en algún otro momento. Tenga en cuenta que su odsalida no fue de un archivo XLS.
John Machin
8
@ AP257: ¿Alguna razón en particular por la que no ha aceptado esta respuesta?
John Machin
Funciona, pero debería ser posible y agradable sobre la marcha con un objeto similar a un archivo que filtra el CSV y se puede pasar csv.readerdirectamente.
gerrit
1
¿No debería fo.write(data.replace('\x00', ''))ser fo.write(data.replace(b'\x00', b''))? Python 3.6 aquí ...
Boern
23
data_initial = open("staff.csv", "rb")
data = csv.reader((line.replace('\0','') for line in data_initial), delimiter=",")

Esto funciona para mi.

doble
fuente
Resuelto para mi caso, los nulos eran los valores '\ 0'. Gracias.
Joab Mendes
19

Leerlo como UTF-16 también fue mi problema.

Aquí está mi código que terminó funcionando:

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

Donde ubicación es el directorio de su archivo csv.

Usuario
fuente
13

También me encontré con este problema. Usando el csvmódulo de Python , estaba tratando de leer un archivo XLS creado en MS Excel y me encontré con el NULL byteerror que estaba obteniendo. Miré a mi alrededor y encontré el módulo xlrd Python para leer y formatear datos de archivos de hoja de cálculo de MS Excel. Con el xlrdmódulo, no solo puedo leer el archivo correctamente, sino que también puedo acceder a muchas partes diferentes del archivo de una manera que antes no podía.

Pensé que podría ayudarte.

ayaz
fuente
7
Gracias por señalar ese módulo. Curiosamente, fui a descargarlo y noté que el autor no era otro que @John_Machin, quien también es el principal comentario sobre esta pregunta.
Evan
11

Convertir la codificación del archivo fuente de UTF-16 a UTF-8 soluciona mi problema.

¿Cómo convertir un archivo a utf-8 en 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)
Patrick Halley
fuente
7

Podrías simplemente incorporar un generador para filtrar los valores nulos si quieres fingir que no existen. Por supuesto, esto supone que los bytes nulos no son realmente parte de la codificación y realmente son algún tipo de artefacto o error erróneo.

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))
woot
fuente
2

¿Por qué estás haciendo esto?

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

Los documentos son bastante claros de que debes hacer esto:

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

El modo debe ser "rb" para leer.

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

Si csvfile es un objeto de archivo, debe abrirse con la bandera 'b' en plataformas donde eso marca la diferencia.

S.Lott
fuente
@ AP257: ¿"No ayuda"? ¿Qué significa? ¿Algún mensaje de error específico?
S.Lott
1
@ S.Lott: Significa que obtiene la misma respuesta que antes. La realidad es que se trata de un archivo camaleón o cambiaformas ... cuando lo descarga odo lo mira en un editor de texto, parece un archivo CSV perfectamente normal. Sin embargo, cuando descarga los primeros bytes con Python repr (), se convierte en un archivo .XLS de Excel (que ha sido renombrado para tener una extensión CSV).
John Machin
@John Machin: "un archivo Excel .XLS (que ha sido renombrado para tener una extensión CSV" Tiene sentido que no se puede procesar en absoluto.
S.Lott
1
@ S.Lott: Con ese contenido, tiene sentido que el módulo csv no pueda procesarlo; sin embargo, el módulo xlrd puede procesarlo. Con sensatez, ninguno de los módulos infiere nada del nombre del archivo de entrada, si de hecho la entrada es un archivo con un nombre.
John Machin
1
@John Machin: "ningún módulo infiere nada del nombre del archivo de entrada". Cierto. Mi marco de aplicación depende de ese hecho. No confiamos en que el nombre del archivo signifique nada, ya que las personas cometen errores ("mienten"). Así que tenemos que comprobar un montón de alternativas hasta que una haga clic.
S.Lott
2

Aparentemente, es un archivo XLS y no un archivo CSV como confirma http://www.garykessler.net/library/file_sigs.html

Xavier Combelle
fuente
No necesariamente, pero sí, esto podría ser una causa. Recibí este error cuando intenté analizar un archivo CSV que Excel guardó desde un archivo XLSX.
Cerin
Con este número mágico, es porque XLSX tiene un número mágico diferente
Xavier Combelle
2

En lugar del lector csv, uso el archivo de lectura y la función de división para la cadena:

lines = open(input_file,'rb') 

for line_all in lines:

    line=line_all.replace('\x00', '').split(";")
Nico el cepillo
fuente
1

Tengo el mismo error. Guardado el archivo en UTF-8 y funcionó.

mikaiscute
fuente
1
Es posible que haya recibido el mismo mensaje de error, pero la causa habría sido diferente: probablemente lo guardó originalmente como UTF-16 (lo que el Bloc de notas llama "Unicode").
John Machin
1

Esto me sucedió cuando creé un archivo CSV con OpenOffice Calc. No sucedió cuando creé el archivo CSV en mi editor de texto, incluso si luego lo edité con Calc.

Resolví mi problema copiando y pegando en mi editor de texto los datos de mi archivo creado por Calc en un nuevo archivo creado por el editor.

user1990371
fuente
1

Tuve el mismo problema al abrir un CSV producido desde un servicio web que insertaba bytes NULL en encabezados vacíos. Hice lo siguiente para limpiar el archivo:

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

Descargo de responsabilidad: tenga en cuenta que esto sobrescribe sus datos originales. Asegúrese de tener una copia de seguridad del mismo. ¡Usted ha sido advertido!

Matthias Kuhn
fuente
0

Para todos aquellos que odian el modo de archivo 'rU': Acabo de intentar abrir un archivo CSV desde una máquina Windows en una Mac con el modo de archivo 'rb' y recibí este error del módulo csv:

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

Abrir el archivo en modo 'rU' funciona bien. Me encanta el modo universal de nueva línea, me ahorra muchos problemas.

Bill bruto
fuente
0

Encontré esto al usar scrapy y obtener un archivo csv comprimido sin tener un middleware correcto para descomprimir el cuerpo de respuesta antes de entregárselo al csvreader. Por lo tanto, el archivo no era realmente un archivo csv y arrojó el line contains NULL byteerror en consecuencia.

Gesias
fuente
0

¿Ha intentado utilizar gzip.open?

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

Estaba intentando abrir un archivo que se había comprimido pero que tenía la extensión '.csv' en lugar de 'csv.gz'. Este error siguió apareciendo hasta que usé gzip.open

Munene iUwej Julius
fuente
-1

Un caso es que: si el archivo CSV contiene filas vacías, este error puede aparecer. Es necesario comprobar la fila antes de proceder a escribir o leer.

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

Resolví mi problema agregando esta verificación en el código.

kirancodificar
fuente