Помилка 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.


Як виглядає od -cперший рядок?
Ігнасіо Васкес-Абрамс

який запит слід запустити, щось на зразок кішки my.csv | од -с | більше? з цим я отримую: 0000000 D відділення F
amil

Як формується CSV? З Excel ви можете спробувати діалект. В іншому випадку дивитися на кажуть: stackoverflow.com/questions/2753022 / ...
ДГ jimbob

Дякую. Це не мій CSV, і, на жаль, я не маю сили це змінити. Я думаю, що він створений як Excel та збережений як CSV (boo). Діалект звучить як гарна ідея - я спробую це!
AP257

Якщо він дійсно був збережений як CSV, він повинен працювати. Я іноді знаходжу - це файли TSV (розділені вкладками), що маскуються під CSV, тому ви можете спробувати встановити роздільник «\ t». Якщо він був збережений як файл Excel, а розширення змінено на CSV, жоден діалект не працюватиме. Я думаю, що вашим єдиним варіантом у цьому випадку буде використання Excel для збереження копій як належного CSV.
Томас К

Відповіді:


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 байт")?


Дуже дякую за цю дуже детальну допомогу. У файлі багато \ 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 тут ...
Boern

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

Це працює для мене.


Вирішено для мого випадку нульовими були значення "\ 0". Дякую.
Йоав Мендес

19

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

Ось мій код, який закінчився:

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

Де розташування - це каталог вашого файлу 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)

7

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

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

Чому ви це робите?

 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
@ S.Lott: Значить, він отримує таку ж відповідь, як і раніше. Дійсність полягає в тому, що він має справу з файлом хамелеона чи перемикача ... коли він скидає його odабо дивиться на нього в текстовому редакторі, це виглядає як абсолютно нормальний файл CSV. Однак, коли він скидає перші кілька байтів за допомогою Python repr (), він виглядає як файл Excel .XLS (це було перейменовано на розширення CSV).
Джон Махін

@John Machin: "файл Excel .XLS (перейменований на розширення CSV". Має сенс, що його взагалі не можна обробити.
S.Lott

1
@ S.Lott: З цим вмістом є сенс, що модуль csv не може його обробити; однак модуль xlrd може його обробити. Зрозуміло, що жоден модуль нічого не виводить з імені вхідного файлу, якщо дійсно вхідний файл - це ім'я.
Джон Махін

1
@John Machin: "жоден модуль нічого не виводить з імені вхідного файлу". Правда. Моя основа заявки залежить від цього факту. Ми не віримо, що ім’я файлу нічого не означає, оскільки люди роблять помилки ("брехня"). Тож нам доведеться перевірити купу альтернатив, поки не клацне один клік.
С.Лотт

2

мабуть, це файл XLS, а не файл CSV, як підтверджують http://www.garykessler.net/library/file_sigs.html


Не обов’язково, але так, це може бути причиною. Я отримав цю помилку, коли спробував розібрати файл CSV, який було збережено Excel з файлу XLSX.
Серін

Завдяки цьому магічному номеру причина XLSX має інше магічне число
Xavier Combelle

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-файлу в новий файл, створений редактором.


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

Я зіткнувся з цим під час використання scrap і витягування zipped csvfile, не маючи правильного проміжного програмного забезпечення, щоб розпакувати тіло відповідей, перш ніж передавати його 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

Я вирішив свою проблему, додавши цей код у код.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.