Ошибка CSV Python: строка содержит нулевой байт

Я работаю с некоторыми 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.

19 ответов

Как говорит @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 output), тогда у вас определенно есть 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") файлы?

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

Это работает для меня.

Чтение его как 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-файла.

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

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

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

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

Преобразование кодировки исходного файла из 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)

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

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

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

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

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

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

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

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

lines = open(input_file,'rb') 

for line_all in lines:

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

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

Я открыл и сохранил исходный файл csv как .csv файл через Excel «Сохранить как», и нулевой байт исчез.

Я думаю, что исходная кодировка для файла, который я получил, была двухбайтовой кодировкой Unicode (каждый второй символ имел нулевой символ), поэтому при сохранении его через excel кодировка была исправлена.

Я получил ту же ошибку. Сохраненный файл в UTF-8 и все заработало.

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

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

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

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

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

Удалить или заменитьnull bytes:

      with open('your_file.csv', 'rb') as file:
    data = file.read().replace(b'\x00', b'')
with open('your_file.csv', 'wb') as file:
    file.write(data)

Что мне помогло, так это более ручной подход к занесению определенных персонажей в черный список. В данных, с которыми я работал, управляющий символ ASCII указывал на то, что строка повреждена. Этот скрипт ищет любые «плохие» символы и, если они найдены, полностью пропускает строку. Предполагается, что заголовок CSV в первой строке не поврежден. При таком подходе поврежденные данные перехватываются еще до того, как они достигнуткоторый затем выдает ошибку нулевого байта.

      import io, csv

# Problematic ASCII control characters.
ascii_control_characters = list(range(0, 31))
ascii_control_characters.append(127) # Delete.
ascii_control_characters.remove(10) # Line feed.
ascii_control_characters.remove(13) # Carriage return.

with open('/foo/bar/baz.csv', 'r') as data_file:
    header = ''

    for index, line in enumerate(data_file):
        # Search line for problematic ASCII characters.
        bad_character_found = False

        for character in line:
            if ord(character) in ascii_control_characters:
                bad_character_found = True
                break

        # If a bad character is found, skip the line altogether.
        if bad_character_found:
            print(
                'Corrupted data found on line: ' + \
                 str(index + 1) + \
                 '. Skipping...'
            )

            continue

        if index == 0:
            header += line
            continue

        csv_data = header + line

        reader = csv.DictReader(io.StringIO(csv_data))

        for row in reader:
            # Process each CSV row here.
            pass

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

Для всех тех, кто ненавидит файловые режимы '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' работает нормально. Я люблю режим универсального перевода строки - он избавляет меня от лишних хлопот.

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

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

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

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

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

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

Другие вопросы по тегам