ข้อผิดพลาด Python CSV: บรรทัดมี 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พูดลักษณะบรรทัดแรกเป็นอย่างไร
Ignacio Vazquez-Abrams

ฉันควรเรียกใช้แบบสอบถามอะไรเช่น cat my.csv | od -c | มากกว่า ? ด้วยสิ่งที่ฉันได้รับ: 0000000 D epartment F amil
AP257

CSV สร้างขึ้นได้อย่างไร จาก excel คุณอาจลองใช้ภาษาถิ่นได้ อย่างอื่นดูที่ say: 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 Compound - e กรัมxls ไฟล์ ผมพบว่า "ในตัวแก้ไขข้อความดูเหมือนว่าไฟล์ CSV สมบูรณ์เหมาะสม" ที่จะไม่น่าเชื่ออย่างเต็มที่ คุณต้องดูไฟล์อื่นไฟล์ CSV ที่ถูกต้องในโฟลเดอร์อื่นหรือในเครื่องอื่นหรือในเวลาอื่น โปรดทราบว่าodผลลัพธ์ของคุณไม่ได้มาจากไฟล์ XLS
John Machin

8
@ AP257: เหตุผลใดที่ทำให้คุณไม่ยอมรับคำตอบนี้?
John Machin

ใช้งานได้ แต่ควรเป็นไปได้และดีในทันทีด้วยวัตถุคล้ายไฟล์ที่กรอง 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" ขอบคุณ.
Joab 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

ตำแหน่งคือไดเร็กทอรีของไฟล์ csv ของคุณ


13

ฉันประสบปัญหานี้เช่นกัน เมื่อใช้csvโมดูลPython ฉันพยายามอ่านไฟล์ XLS ที่สร้างใน MS Excel และพบNULL byteข้อผิดพลาดที่คุณได้รับ ฉันมองไปรอบ ๆ และพบโมดูลxlrd Python สำหรับอ่านและจัดรูปแบบข้อมูลจากไฟล์สเปรดชีต MS Excel ด้วยxlrdโมดูลนี้ฉันไม่เพียง แต่สามารถอ่านไฟล์ได้อย่างถูกต้องเท่านั้น แต่ฉันยังสามารถเข้าถึงส่วนต่างๆของไฟล์ในแบบที่ฉันทำไม่ได้มาก่อน

ฉันคิดว่ามันอาจช่วยคุณได้


7
ขอขอบคุณที่ชี้ให้เห็นโมดูลนั้น ที่น่าสนใจพอฉันไปดาวน์โหลดและสังเกตว่าผู้เขียนไม่ใช่ใครอื่นนอกจาก @John_Machin ซึ่งเป็นผู้แสดงความคิดเห็นสูงสุดในคำถามนี้
Evan

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

คุณสามารถอินไลน์เครื่องกำเนิดไฟฟ้าเพื่อกรองค่า null ได้หากคุณต้องการแสร้งทำเป็นว่าไม่มีอยู่จริง แน่นอนว่านี่เป็นการสมมติว่าไบต์ว่างไม่ได้เป็นส่วนหนึ่งของการเข้ารหัสและเป็นสิ่งประดิษฐ์หรือจุดบกพร่องที่ผิดพลาด

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: "ไม่ช่วย"? หมายถึงอะไร? ข้อความแสดงข้อผิดพลาดใด ๆ ?
ล็อตต์

1
@ S.Lott: หมายความว่าเขาได้รับคำตอบเหมือนเดิม ความจริงก็คือเขากำลังจัดการกับไฟล์กิ้งก่าหรือไฟล์จำแลง ... เมื่อเขาทิ้งมันด้วยodหรือดูมันในโปรแกรมแก้ไขข้อความดูเหมือนไฟล์ CSV ปกติอย่างสมบูรณ์ อย่างไรก็ตามเมื่อเขาทิ้งสองสามไบต์แรกด้วย Python repr () มันจะทำให้เหมือนกับไฟล์ Excel .XLS (ซึ่งถูกเปลี่ยนชื่อให้มีนามสกุล CSV)
John Machin

@ John Machin: "ไฟล์ Excel .XLS (ที่ถูกเปลี่ยนชื่อเป็นนามสกุล CSV" ทำให้รู้สึกว่าไม่สามารถประมวลผลได้เลย
ล็อตต์

1
@ S.Lott: ด้วยเนื้อหาดังกล่าวทำให้รู้สึกว่าโมดูล csv ไม่สามารถประมวลผลได้ อย่างไรก็ตามโมดูล xlrd สามารถประมวลผลได้ อย่างมีเหตุผลโมดูลทั้งสองไม่มีการอนุมานอะไรจากชื่อของไฟล์อินพุตหากอินพุตเป็นไฟล์ที่มีชื่อ
John Machin

1
@ John Machin: "โมดูลทั้งสองไม่มีการอนุมานอะไรจากชื่อของไฟล์อินพุต" จริง. กรอบการสมัครของฉันขึ้นอยู่กับข้อเท็จจริงนั้น เราไม่เชื่อว่าชื่อไฟล์จะหมายถึงอะไรเนื่องจากมีคนทำผิด ("โกหก") ดังนั้นเราต้องตรวจสอบทางเลือกมากมายจนกว่าจะคลิกเพียงครั้งเดียว
ล็อตต์

2

เห็นได้ชัดว่าเป็นไฟล์ XLS ไม่ใช่ไฟล์ CSV เนื่องจากhttp://www.garykessler.net/library/file_sigs.htmlยืนยัน


ไม่จำเป็น แต่ใช่นี่อาจเป็นสาเหตุ ฉันได้รับข้อผิดพลาดนี้เมื่อพยายามแยกวิเคราะห์ไฟล์ CSV ที่ Excel บันทึกจากไฟล์ XLSX
Cerin

ด้วยเลขวิเศษนี้ทำให้ 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 (สิ่งที่ Notepad เรียกว่า "Unicode")
John Machin

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' ใช้งานได้ดี ฉันชอบโหมด universal-newline - มันช่วยให้ฉันไม่ยุ่งยากมาก


0

ฉันพบสิ่งนี้เมื่อใช้ scrapy และดึง 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

ฉันแก้ไขปัญหาของฉันโดยเพิ่มการตรวจสอบนี้ในรหัส

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.