Kesalahan CSV Python: baris berisi byte NULL

102

Saya sedang mengerjakan beberapa file CSV, dengan kode berikut:

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

Dan satu file menimbulkan kesalahan ini:

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

Apa yang dapat saya? Google tampaknya menyarankan bahwa itu mungkin file Excel yang disimpan sebagai .csv secara tidak benar. Apakah ada cara untuk mengatasi masalah ini dengan Python?

== UPDATE ==

Mengikuti komentar @ JohnMachin di bawah ini, saya mencoba menambahkan baris ini ke skrip saya:

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

Dan inilah output yang saya dapatkan:

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

Jadi file tersebut memang mengandung byte NUL.

AP257
sumber
Seperti apa od -cbaris pertama itu?
Ignacio Vazquez-Abrams
kueri apa yang harus saya jalankan, seperti cat my.csv | od -c | lebih? dengan itu saya mendapatkan: 0000000 D epartment F amil
AP257
Bagaimana CSV dibuat? Dari excel, Anda mungkin bisa mencoba dialek. Jika tidak, lihat katakan: stackoverflow.com/questions/2753022/…
dr jimbob
Terima kasih. Ini bukan CSV saya, dan sayangnya saya tidak memiliki kekuatan untuk mengubahnya. Saya pikir itu telah dibuat sebagai Excel dan disimpan sebagai CSV (boo). Sebuah dialek terdengar seperti ide yang bagus - Saya akan mencobanya!
AP257
Jika itu benar-benar disimpan sebagai CSV, itu seharusnya berfungsi. Satu hal yang terkadang saya temukan adalah file TSV (dipisahkan tab) yang menyamar sebagai CSV, jadi Anda dapat mencoba menyetel pembatas '\ t'. Jika telah disimpan sebagai file Excel, dan ekstensi diubah menjadi CSV, tidak ada dialek yang akan berfungsi. Saya pikir satu-satunya pilihan Anda dalam hal ini adalah menggunakan Excel untuk menyimpan salinan sebagai CSV yang tepat.
Thomas K

Jawaban:

104

Seperti yang dikatakan @ S. Lott, Anda harus membuka file Anda dalam mode 'rb', bukan mode 'rU'. Namun itu mungkin TIDAK menyebabkan masalah Anda saat ini. Sejauh yang saya tahu, menggunakan mode 'rU' akan mengacaukan Anda jika ada yang tertanam \rdi data, tetapi tidak menyebabkan drama lain. Saya juga mencatat bahwa Anda memiliki beberapa file (semua dibuka dengan 'rU' ??) tetapi hanya satu yang menyebabkan masalah.

Jika modul csv mengatakan bahwa Anda memiliki byte "NULL" (pesan konyol, harus "NUL") di file Anda, maka Anda perlu memeriksa apa yang ada di file Anda. Saya menyarankan Anda melakukan ini bahkan jika menggunakan 'rb' membuat masalah hilang.

repr()adalah (atau ingin menjadi) teman debugging Anda. Ini akan menunjukkan dengan jelas apa yang Anda miliki, dalam mode platform independen (yang berguna untuk pembantu yang tidak menyadari apa yang odsedang atau dilakukan). Melakukan hal ini:

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

dan dengan hati-hati salin / tempel (jangan ketik ulang) hasilnya ke dalam edit pertanyaan Anda (bukan menjadi komentar).

Perhatikan juga bahwa jika file benar-benar cerdik mis. Tidak ada \ r atau \ n dalam jarak yang wajar dari awal file, nomor baris yang dilaporkan oleh reader.line_numakan (tidak membantu) 1. Temukan di mana yang pertama \x00(jika ada) dengan melakukan

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

dan pastikan bahwa Anda membuang setidaknya banyak byte dengan repr atau od.

Apa yang data.count('\x00')memberitahumu? Jika ada banyak, Anda mungkin ingin melakukan sesuatu seperti

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

sehingga Anda dapat melihat byte NUL dalam konteks.

Jika Anda dapat melihat \x00di output (atau \0di od -coutput Anda ), maka Anda pasti memiliki byte NUL di file, dan Anda perlu melakukan sesuatu seperti ini:

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

Omong-omong, apakah Anda sudah melihat file (termasuk beberapa baris terakhir) dengan editor teks? Apakah itu benar-benar terlihat seperti file CSV yang wajar seperti file lainnya (tanpa pengecualian "NULL byte")?

John Machin
sumber
Terima kasih banyak atas bantuan yang sangat mendetail ini. Ada banyak \ x00 karakter dalam file (lihat edit untuk pertanyaan) - ini aneh, karena dalam editor teks ini terlihat seperti file CSV yang masuk akal.
AP257
1
@ AP257: '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1adalah "tanda tangan" yang menunjukkan file Dokumen Gabungan OLE2 - misalnya file .XLS Excel 97-2003 . Saya menemukan "dalam editor teks, sepertinya file CSV yang masuk akal" benar - benar tidak dapat dipercaya . Anda pasti telah melihat file yang berbeda, file CSV yang valid, di folder lain atau di komputer lain atau di lain waktu. Perhatikan bahwa odkeluaran Anda bukan dari file XLS.
John Machin
8
@ AP257: Adakah alasan khusus Anda belum menerima jawaban ini?
John Machin
Berfungsi, tetapi harus memungkinkan dan menyenangkan dengan cepat dengan objek seperti file yang memfilter CSV dan dapat diteruskan ke csv.readersecara langsung.
gerrit
1
Tidak fo.write(data.replace('\x00', ''))seharusnya fo.write(data.replace(b'\x00', b''))? Python 3.6 di sini ...
Boern
23
data_initial = open("staff.csv", "rb")
data = csv.reader((line.replace('\0','') for line in data_initial), delimiter=",")

Ini berhasil untuk saya.

dua kali lipat
sumber
Dipecahkan untuk kasus saya, null adalah nilai '\ 0'. Terima kasih.
Joab Mendes
19

Membacanya sebagai UTF-16 juga merupakan masalah saya.

Inilah kode saya yang akhirnya berfungsi:

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

Dimana lokasi adalah direktori file csv Anda.

Pengguna
sumber
13

Saya mengalami masalah ini juga. Menggunakan csvmodul Python , saya mencoba membaca file XLS yang dibuat di MS Excel dan mengalami NULL bytekesalahan yang Anda dapatkan. Saya melihat sekeliling dan menemukan modul Python xlrd untuk membaca dan memformat data dari file spreadsheet MS Excel. Dengan xlrdmodul ini, saya tidak hanya dapat membaca file dengan benar, tetapi saya juga dapat mengakses banyak bagian file dengan cara yang tidak dapat saya lakukan sebelumnya.

Saya pikir itu mungkin membantu Anda.

ayaz
sumber
7
Terima kasih telah menunjukkan modul itu. Yang cukup menarik, saya pergi untuk mendownloadnya dan melihat bahwa penulisnya tidak lain adalah @John_Machin yang juga merupakan komentar teratas untuk pertanyaan ini.
Evan
11

Mengonversi pengkodean file sumber dari UTF-16 ke UTF-8 memecahkan masalah saya.

Bagaimana cara mengonversi file ke utf-8 dengan 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
sumber
7

Anda bisa membuat generator sebaris untuk menyaring nilai null jika Anda ingin berpura-pura tidak ada. Tentu saja ini mengasumsikan byte nol sebenarnya bukan bagian dari pengkodean dan sebenarnya adalah semacam artefak atau bug yang salah.

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
sumber
2

Mengapa kau melakukan ini?

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

Dokumennya cukup jelas bahwa Anda harus melakukan ini:

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

Modusnya harus "rb" untuk membaca.

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

Jika csvfile adalah sebuah objek file, itu harus dibuka dengan tanda 'b' pada platform yang membuat perbedaan.

S. Lott
sumber
@ AP257: "Tidak membantu"? Artinya apa? Ada pesan kesalahan khusus?
S. Lott
1
@ S. Lott: Berarti dia mendapat jawaban yang sama seperti sebelumnya. Kenyataannya adalah dia berurusan dengan file bunglon atau shapeshifter ... ketika dia membuangnya odatau melihatnya di editor teks, itu terlihat seperti file CSV yang normal. Namun ketika dia membuang beberapa byte pertama dengan Python repr (), itu menjadi seperti file .XLS Excel (yang telah diganti namanya menjadi memiliki ekstensi CSV).
John Machin
@ John Machin: "file .XLS Excel (yang telah diubah namanya menjadi ekstensi CSV" Masuk akal bahwa file tersebut tidak dapat diproses sama sekali.
S.Lott
1
@ S.Lott: Dengan konten tersebut, masuk akal bahwa modul csv tidak dapat memprosesnya; namun modul xlrd dapat memprosesnya. Seharusnya, tidak ada modul yang menyimpulkan apapun dari nama file input, jika memang inputnya adalah file dengan nama.
John Machin
1
@ John Machin: "tidak ada modul yang menyimpulkan apa pun dari nama file input". Benar. Kerangka aplikasi saya bergantung pada fakta itu. Kami tidak percaya nama file berarti apa-apa, karena orang membuat kesalahan ("berbohong"). Jadi kita harus memeriksa banyak alternatif hingga satu klik.
S. Lott
2

tampaknya ini adalah file XLS dan bukan file CSV seperti yang http://www.garykessler.net/library/file_sigs.html konfirmasi

Xavier Combelle
sumber
Belum tentu, tapi ya, ini bisa jadi penyebabnya. Saya mendapatkan kesalahan ini ketika saya mencoba mengurai file CSV yang disimpan oleh Excel dari file XLSX.
Cerin
Dengan angka ajaib inilah penyebab XLSX memiliki angka ajaib yang berbeda
Xavier Combelle
2

Alih-alih pembaca csv, saya menggunakan file baca dan fungsi split untuk string:

lines = open(input_file,'rb') 

for line_all in lines:

    line=line_all.replace('\x00', '').split(";")
Nico The Brush
sumber
1

Saya mendapat kesalahan yang sama. Menyimpan file dalam UTF-8 dan berhasil.

mikaiscute
sumber
1
Anda mungkin mendapatkan pesan kesalahan yang sama, tetapi penyebabnya akan berbeda - Anda mungkin menyimpannya pada awalnya sebagai UTF-16 (yang oleh Notepad disebut "Unicode").
John Machin
1

Ini terjadi pada saya ketika saya membuat file CSV dengan OpenOffice Calc. Itu tidak terjadi ketika saya membuat file CSV di editor teks saya, bahkan jika saya kemudian mengeditnya dengan Calc.

Saya memecahkan masalah saya dengan menyalin-menempel di editor teks saya data dari file yang saya buat Calc ke file yang dibuat editor baru.

pengguna1990371
sumber
1

Saya memiliki masalah yang sama membuka CSV yang dihasilkan dari layanan web yang memasukkan byte NULL di header kosong. Saya melakukan hal berikut untuk membersihkan file:

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

Penafian: Ketahuilah bahwa ini menimpa data asli Anda. Pastikan Anda memiliki salinan cadangannya. Anda telah diperingatkan!

Matthias Kuhn
sumber
0

Untuk semua pembenci filemode 'rU': Saya baru saja mencoba membuka file CSV dari mesin Windows di Mac dengan filemode 'rb' dan saya mendapatkan kesalahan ini dari modul csv:

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

Membuka file dalam mode 'rU' berfungsi dengan baik. Saya suka mode universal-newline - ini menghemat banyak kerumitan.

Bill Gross
sumber
0

Saya mengalami ini saat menggunakan scrapy dan mengambil file csvfile yang sudah di-zip tanpa middleware yang benar untuk mengekstrak badan respons sebelum menyerahkannya ke csvreader. Karenanya file tersebut sebenarnya bukan file csv dan memberikan line contains NULL bytekesalahan yang sesuai.

Gesias
sumber
0

Sudahkah Anda mencoba menggunakan gzip.open?

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

Saya mencoba membuka file yang telah dikompresi tetapi memiliki ekstensi '.csv', bukan 'csv.gz'. Kesalahan ini terus muncul sampai saya menggunakan gzip.open

Munene iUwej Julius
sumber
-1

Salah satu kasusnya adalah - Jika file CSV berisi baris kosong, kesalahan ini mungkin muncul. Memeriksa baris diperlukan sebelum kita melanjutkan untuk menulis atau membaca.

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

Saya memecahkan masalah saya dengan menambahkan cek ini di kode.

kirancodify
sumber