Ошибка CSV Python: строка содержит NULL-байт

102

Я работаю с некоторыми CSV-файлами со следующим кодом:

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

И один файл выдает эту ошибку:

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

Что я могу сделать? Google, похоже, предполагает, что это может быть файл Excel, который был неправильно сохранен как .csv. Есть ли способ обойти эту проблему в Python?

== ОБНОВЛЕНИЕ ==

Следуя приведенному ниже комментарию @ JohnMachin, я попытался добавить эти строки в свой скрипт:

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

И вот результат, который я получил:

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

Таким образом, файл действительно содержит NUL байтов.

AP257
источник
Как od -cговорит первая строка?
Игнасио Васкес-Абрамс
какой запрос я должен запустить, например cat my.csv | od -c | Больше ? с этим я получаю: 0000000 Отделение F amil
AP257,
Как создается CSV? В excel вы можете попробовать диалект. В противном случае посмотрите, скажем: stackoverflow.com/questions/2753022/…
dr jimbob
Спасибо. Это не мой CSV, и, к сожалению, у меня нет возможности его изменить. Я думаю, что он был создан как Excel и сохранен как CSV (boo). Диалект - неплохая идея - я попробую!
AP257,
Если он действительно был сохранен как CSV, он должен работать. Иногда я нахожу, что файлы TSV (разделенные табуляцией) маскируются как CSV, поэтому вы можете попробовать установить разделитель '\ t'. Если он был сохранен как файл Excel, а расширение изменено на CSV, диалект не будет работать. Я думаю, что ваш единственный вариант в этом случае - использовать Excel для сохранения копий в формате CSV.
Thomas K

Ответы:

104

Как говорит @ S.Lott, вы должны открывать свои файлы в режиме «rb», а не в режиме «rU». Однако это может НЕ быть причиной вашей текущей проблемы. Насколько мне известно, использование режима «rU» может вас испортить, если они встроены \rв данные, но не вызовет никаких других проблем. Я также отмечу, что у вас есть несколько файлов (все открыты с помощью 'rU' ??), но только один вызывает проблемы.

Если модуль csv сообщает, что в вашем файле есть байт «NULL» (глупое сообщение, должно быть «NUL»), то вам необходимо проверить, что находится в вашем файле. Я бы посоветовал вам сделать это, даже если использование rb решит проблему.

repr()является (или хочет быть) вашим другом по отладке. Он однозначно покажет, что у вас есть, независимо от платформы (что полезно для помощников, которые не знают, что odесть или делает). Сделай это:

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

и аккуратно скопируйте / вставьте (не вводите повторно) результат в редактирование вашего вопроса (не в комментарий).

Также обратите внимание, что если файл действительно изворотливый, например, нет \ r или \ n на разумном расстоянии от начала файла, номер строки, сообщаемый с помощью, reader.line_numбудет (бесполезно) 1. Найдите, где находится первое \x00(если есть), выполнив

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

и убедитесь, что вы сбрасываете по крайней мере это количество байтов с помощью repr или od.

Что data.count('\x00')вам сказать? Если их много, вы можете сделать что-нибудь вроде

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

так что вы можете видеть байты NUL в контексте.

Если вы видите \x00на выходе (или \0на своем od -cвыходе), то у вас определенно есть NUL байт (ы) в файле, и вам нужно будет сделать что-то вроде этого:

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

Кстати, вы просматривали файл (включая последние несколько строк) в текстовом редакторе? Действительно ли он похож на разумный CSV-файл, как и другие (без исключения "NULL byte") файлы?

Джон Мачин
источник
Большое спасибо за эту очень подробную помощь. В файле много символов \ x00 (см. Правка вопроса) - это странно, потому что в текстовом редакторе он выглядит как вполне разумный CSV-файл.
AP257
1
@ AP257: '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1это «подпись», обозначающая файл составного документа OLE2 - например, файл Excel 97-2003 .XLS . Я считаю, что фраза «в текстовом редакторе выглядит как вполне разумный CSV-файл» совершенно невероятно . Вы, должно быть, просматривали другой файл, действительный файл CSV, в другой папке, на другом компьютере или в другое время. Обратите внимание, что ваш odвывод не был из файла XLS.
Джон Мачин
8
@ AP257: Есть какая-то конкретная причина, по которой вы не приняли этот ответ?
Джон Мачин
Работает, но должно быть возможным и приятным на лету с файловым объектом, который фильтрует CSV и может быть передан csv.readerнапрямую.
gerrit
1
Не должно fo.write(data.replace('\x00', ''))быть fo.write(data.replace(b'\x00', b''))? Python 3.6 здесь ...
Берн
23
data_initial = open("staff.csv", "rb")
data = csv.reader((line.replace('\0','') for line in data_initial), delimiter=",")

У меня это работает.

двойной
источник
Решено для моего случая, нулевым значением были значения '\ 0'. Спасибо.
Mendes
19

Чтение его как UTF-16 тоже было моей проблемой.

Вот мой код, который в итоге заработал:

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

Где location - это каталог вашего CSV-файла.

Пользователь
источник
13

Я тоже столкнулся с этой проблемой. Используя csvмодуль Python , я пытался прочитать файл XLS, созданный в MS Excel, и столкнулся с NULL byteошибкой, которую вы получали. Я огляделся и нашел модуль xlrd Python для чтения и форматирования данных из файлов электронных таблиц MS Excel. С помощью xlrdмодуля я не только могу правильно читать файл, но также могу получить доступ ко многим различным частям файла, чего раньше не мог.

Я думал, это может тебе помочь.

аяз
источник
7
Спасибо, что указали на этот модуль. Интересно, что я пошел его скачать и заметил, что автором был никто иной, как @John_Machin, который также является главным комментарием по этому вопросу.
Эван
11

Преобразование кодировки исходного файла из UTF-16 в UTF-8 решает мою проблему.

Как преобразовать файл в utf-8 в 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)
Патрик Галлей
источник
8

Вы можете просто встроить генератор для фильтрации нулевых значений, если хотите сделать вид, что их не существует. Конечно, предполагается, что нулевые байты на самом деле не являются частью кодировки, а представляют собой своего рода ошибочный артефакт или ошибку.

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
источник
2

Почему вы это делаете?

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

В документации довольно ясно сказано, что вы должны сделать это:

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

Для чтения режим должен быть "rb".

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

Если csvfile является файловым объектом, он должен быть открыт с флагом 'b' на платформах, где это имеет значение.

С.Лотт
источник
@ AP257: «Не помогает»? Значит что? Какие-нибудь конкретные сообщения об ошибках?
S.Lott
1
@ С.Лотт: Значит, он получит тот же ответ, что и раньше. Реальность такова, что он имеет дело с файлом хамелеона или оборотня ... когда он выгружает его odили просматривает в текстовом редакторе, он выглядит как совершенно нормальный файл CSV. Однако, когда он выгружает первые несколько байтов с помощью Python repr (), он становится похожим на файл Excel .XLS (который был переименован в расширение CSV).
Джон Мачин
@John Machin: "файл Excel .XLS (который был переименован в расширение CSV" Имеет смысл, что он вообще не может быть обработан.
S.Lott
1
@ S.Lott: Имея такой контент, очевидно, что модуль csv не может его обработать; однако модуль xlrd может его обработать. Разумно, что ни один из модулей не выводит ничего из имени входного файла, если действительно входной файл является файлом с именем.
Джон Мачин,
1
@John Machin: «ни один модуль не выводит ничего из имени входного файла». Правда. Структура моего приложения зависит от этого факта. Мы не доверяем имени файла, чтобы что-то значить, поскольку люди совершают ошибки («лгут»). Поэтому мы должны проверять кучу альтернатив до одного щелчка.
S.Lott
2

очевидно, что это файл XLS, а не файл CSV, как подтверждают http://www.garykessler.net/library/file_sigs.html

Ксавье Комбель
источник
Не обязательно, но да, это могло быть причиной. Я получил эту ошибку, когда попытался проанализировать файл CSV, сохраненный Excel, из файла XLSX.
Cerin
Это магическое число является причиной того, что у XLSX другое магическое число
Ксавье Комбелль
2

Вместо читателя csv я использую функцию чтения файла и функцию разделения для строки:

lines = open(input_file,'rb') 

for line_all in lines:

    line=line_all.replace('\x00', '').split(";")
Нико Кисть
источник
1

У меня такая же ошибка. Сохранил файл в UTF-8, и все заработало.

мика
источник
1
Возможно, у вас было такое же сообщение об ошибке, но причина была бы в другой - вы, вероятно, сохранили его изначально как UTF-16 (то, что Блокнот называет «Unicode»).
Джон Мачин
1

Это случилось со мной, когда я создал файл CSV с помощью OpenOffice Calc. Этого не произошло, когда я создал файл CSV в своем текстовом редакторе, даже если позже редактировал его с помощью Calc.

Я решил свою проблему, скопировав в текстовом редакторе данные из файла, созданного с помощью Calc, в новый файл, созданный редактором.

user1990371
источник
1

У меня была такая же проблема с открытием CSV, созданного из веб-службы, которая вставляла байты NULL в пустые заголовки. Для очистки файла я сделал следующее:

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

Отказ от ответственности: имейте в виду, что это перезаписывает ваши исходные данные. Убедитесь, что у вас есть его резервная копия. Вы были предупреждены!

Маттиас Кун
источник
0

Для всех тех, кто ненавидит файловый режим 'rU': я просто попытался открыть файл CSV с компьютера Windows на Mac с файловым режимом 'rb' и получил эту ошибку из модуля csv:

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

Открытие файла в режиме «rU» работает нормально. Мне нравится универсальный режим новой строки - он избавляет меня от лишних хлопот.

Билл Гросс
источник
0

Я столкнулся с этим при использовании scrapy и извлечении заархивированного csv-файла без правильного промежуточного программного обеспечения для распаковки тела ответа перед передачей его csvreader. Следовательно, файл на самом деле не был файлом csv и соответственно выдавал line contains NULL byteошибку.

Гезиас
источник
0

Вы пробовали использовать gzip.open?

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

Я пытался открыть файл, который был сжат, но имел расширение «.csv» вместо «csv.gz». Эта ошибка продолжала появляться, пока я не использовал gzip.open

Мунене Ювей Юлиус
источник
-1

В одном случае - если файл CSV содержит пустые строки, эта ошибка может появиться. Перед тем, как мы перейдем к записи или чтению, необходимо проверить строку.

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

Я решил свою проблему, добавив эту проверку в код.

Киранкодификация
источник