Ошибка 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
Я решил свою проблему, добавив эту проверку в коде.