Lỗi CSV trong Python: dòng chứa byte NULL


102

Tôi đang làm việc với một số tệp CSV, với mã sau:

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

Và một tệp đang gặp lỗi này:

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

Tôi có thể làm gì? Google dường như cho rằng đó có thể là một tệp Excel được lưu dưới dạng .csv không đúng cách. Có cách nào tôi có thể giải quyết vấn đề này bằng Python không?

== CẬP NHẬT ==

Theo nhận xét của @ JohnMachin bên dưới, tôi đã thử thêm những dòng này vào tập lệnh của mình:

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

Và đây là kết quả tôi nhận được:

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

Vì vậy, tệp thực sự chứa NUL byte.


od -cnói cái nhìn dòng đầu tiên như thế nào?
Ignacio Vazquez-Abrams

tôi nên chạy truy vấn nào, chẳng hạn như cat my.csv | od -c | hơn ? với điều đó tôi nhận được: 0000000 D epartment F
amil

CSV được tạo như thế nào? Từ excel, bạn có thể thử một phương ngữ. Nếu không nhìn vào nói: stackoverflow.com/questions/2753022/...
dr jimbob

Cảm ơn. Đó không phải là CSV của tôi và rất tiếc là tôi không có quyền thay đổi nó. Tôi nghĩ rằng nó đã được tạo dưới dạng Excel và được lưu dưới dạng CSV (boo). Một phương ngữ nghe có vẻ là một ý kiến ​​hay - Tôi sẽ thử!
AP257

Nếu nó thực sự được lưu dưới dạng CSV, nó sẽ hoạt động. Một điều đôi khi tôi thấy là các tệp TSV (được phân tách bằng tab) giả mạo là CSV, vì vậy bạn có thể thử đặt dấu phân cách là '\ t'. Nếu nó được lưu dưới dạng tệp Excel và phần mở rộng được thay đổi thành CSV, thì không có phương ngữ nào hoạt động. Tôi nghĩ lựa chọn duy nhất của bạn trong trường hợp đó sẽ là sử dụng Excel để lưu các bản sao dưới dạng CSV thích hợp.
Thomas K

Câu trả lời:


104

Như @ S.Lott nói, bạn nên mở tệp của mình ở chế độ 'rb', không phải chế độ 'rU'. Tuy nhiên điều đó có thể KHÔNG gây ra vấn đề hiện tại của bạn. Theo như tôi biết, việc sử dụng chế độ 'rU' sẽ khiến bạn rối tung lên nếu có \rdữ liệu được nhúng vào, nhưng không gây ra bất kỳ bộ phim truyền hình nào khác. Tôi cũng lưu ý rằng bạn có một số tệp (tất cả đều được mở bằng 'rU' ??) nhưng chỉ một tệp gây ra sự cố.

Nếu mô-đun csv nói rằng bạn có byte "NULL" (thông báo ngớ ngẩn, phải là "NUL") trong tệp của bạn, thì bạn cần kiểm tra xem có gì trong tệp của mình. Tôi khuyên bạn nên làm điều này ngay cả khi sử dụng 'rb' làm cho vấn đề biến mất.

repr()là (hoặc muốn trở thành) người bạn gỡ lỗi của bạn. Nó sẽ hiển thị rõ ràng những gì bạn đã có, theo một cách độc lập với nền tảng (điều này rất hữu ích cho những người trợ giúp không biết những gì odđang làm hoặc đang làm). Làm cái này:

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

và cẩn thận sao chép / dán (không nhập lại) kết quả vào bản chỉnh sửa câu hỏi của bạn (không phải vào nhận xét).

Cũng lưu ý rằng nếu tệp thực sự khó hiểu, chẳng hạn như không có \ r hoặc \ n trong khoảng cách hợp lý từ đầu tệp, số dòng được báo cáo reader.line_numsẽ là (vô ích) 1. Tìm vị trí đầu tiên \x00(nếu có) bằng cách

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

và đảm bảo rằng bạn kết xuất ít nhất nhiều byte đó với repr hoặc od.

Điều gì data.count('\x00')cho bạn biết? Nếu có nhiều, bạn có thể muốn làm điều gì đó như

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

để bạn có thể thấy các byte NUL trong ngữ cảnh.

Nếu bạn có thể thấy \x00trong đầu ra (hoặc \0trong od -cđầu ra của bạn ), thì bạn chắc chắn có (các) byte NUL trong tệp và bạn sẽ cần phải làm như sau:

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

Nhân tiện, bạn đã xem tệp (bao gồm vài dòng cuối cùng) bằng trình soạn thảo văn bản chưa? Nó có thực sự giống một tệp CSV hợp lý giống như các tệp khác (không có ngoại lệ "byte NULL") không?


Cảm ơn bạn rất nhiều vì sự giúp đỡ rất chi tiết này. Có rất nhiều ký tự \ x00 trong tệp (xem phần chỉnh sửa cho câu hỏi) - thật kỳ lạ, vì trong trình soạn thảo văn bản, nó trông giống như một tệp CSV hoàn toàn hợp lý.
AP257

1
@ AP257: '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1là "chữ ký" biểu thị tệp Tài liệu kết hợp OLE2 - ví dụ: tệp Excel 97-2003 .XLS . Tôi thấy "trong một trình soạn thảo văn bản, nó trông giống như một tệp CSV hoàn toàn hợp lý" đến mức khó tin . Bạn phải đang xem một tệp khác, một tệp CSV hợp lệ, trong một thư mục khác hoặc trên một máy khác hoặc vào một thời điểm nào đó. Lưu ý rằng odđầu ra của bạn không phải từ tệp XLS.
John Machin

8
@ AP257: Có lý do cụ thể nào mà bạn chưa chấp nhận câu trả lời này không?
John Machin,

Hoạt động, nhưng phải khả thi và tốt khi đang di chuyển với một đối tượng giống tệp có chức năng lọc CSV và có thể được chuyển csv.readertrực tiếp đến .
gerrit

1
Không nên fo.write(data.replace('\x00', ''))fo.write(data.replace(b'\x00', b''))? Python 3.6 ở đây ...
Boern

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

Điều này làm việc cho tôi.


Đã giải quyết cho trường hợp của tôi, null là các giá trị '\ 0'. Cảm ơn.
Joab Mendes

19

Đọc nó là UTF-16 cũng là vấn đề của tôi.

Đây là mã của tôi đã hoạt động:

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

Vị trí là thư mục của tệp csv của bạn.


13

Tôi cũng gặp phải vấn đề này. Sử dụng csvmô-đun Python , tôi đang cố đọc tệp XLS được tạo trong MS Excel và gặp phải NULL bytelỗi mà bạn đang gặp phải. Tôi đã xem xét xung quanh và tìm thấy mô-đun Python xlrd để đọc và định dạng dữ liệu từ các tệp bảng tính MS Excel. Với xlrdmô-đun, tôi không chỉ có thể đọc tệp đúng cách mà còn có thể truy cập nhiều phần khác nhau của tệp theo cách mà trước đây tôi không thể.

Tôi nghĩ nó có thể giúp bạn.


7
Cảm ơn vì đã chỉ ra mô-đun đó. Khá thú vị, tôi đã tải xuống và nhận thấy tác giả không ai khác chính là @John_Machin, người cũng là người đứng đầu bình luận về câu hỏi này.
Evan

11

Chuyển đổi mã hóa của tệp nguồn từ UTF-16 sang UTF-8 giải quyết vấn đề của tôi.

Làm thế nào để chuyển đổi một tệp thành utf-8 trong 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

Bạn chỉ có thể nội dòng một trình tạo để lọc ra các giá trị null nếu bạn muốn giả sử chúng không tồn tại. Tất nhiên điều này là giả định các byte rỗng không thực sự là một phần của mã hóa và thực sự là một số loại lỗi hoặc lỗi tạo tác sai lầm.

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

Tại sao anh làm điều này?

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

Các tài liệu khá rõ ràng rằng bạn phải làm điều này:

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

Chế độ phải là "rb" để đọc.

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

Nếu csvfile là một đối tượng tệp, nó phải được mở bằng cờ 'b' trên các nền tảng tạo ra sự khác biệt.


@ AP257: "Không giúp được gì"? Nghĩa là gì? Bất kỳ thông báo lỗi cụ thể?
S.Lott

1
@ S.Lott: Có nghĩa là anh ấy nhận được câu trả lời giống như trước đây. Thực tế là anh ta đang xử lý một tệp tắc kè hoa hoặc tệp shapehifter ... khi anh ta đổ odhoặc xem nó trong trình soạn thảo văn bản, nó trông giống như một tệp CSV hoàn toàn bình thường. Tuy nhiên, khi anh ta kết xuất một vài byte đầu tiên với Python repr (), nó sẽ giống như một tệp Excel .XLS (đã được đổi tên để có phần mở rộng CSV).
John Machin

@John Machin: "một tệp Excel .XLS (đã được đổi tên để có phần mở rộng CSV" Có nghĩa là nó không thể được xử lý.
S.Lott

1
@ S.Lott: Với nội dung đó, có nghĩa là mô-đun csv không thể xử lý nó; tuy nhiên mô-đun xlrd có thể xử lý nó. Một cách hợp lý, không mô-đun nào suy ra bất cứ điều gì từ tên của tệp đầu vào, nếu thực sự đầu vào là một tệp có tên.
John Machin

1
@John Machin: "không mô-đun nào suy ra bất cứ điều gì từ tên của tệp đầu vào". Thật. Khung ứng dụng của tôi phụ thuộc vào thực tế đó. Chúng tôi không tin rằng tên tệp có ý nghĩa gì, vì mọi người mắc lỗi ("nói dối"). Vì vậy, chúng tôi phải kiểm tra một loạt các lựa chọn thay thế cho đến khi một cú nhấp chuột.
S.Lott


2

Thay vì trình đọc csv, tôi sử dụng đọc tệp và chức năng tách cho chuỗi:

lines = open(input_file,'rb') 

for line_all in lines:

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

1

Tôi cũng gặp lỗi tương tự. Đã lưu tệp trong UTF-8 và nó đã hoạt động.


1
Bạn có thể gặp phải thông báo lỗi tương tự, nhưng nguyên nhân sẽ khác - bạn có thể đã lưu thông báo ban đầu dưới dạng UTF-16 (cái mà Notepad gọi là "Unicode").
John Machin

1

Điều này đã xảy ra với tôi khi tôi tạo tệp CSV bằng OpenOffice Calc. Điều này đã không xảy ra khi tôi tạo tệp CSV trong trình soạn thảo văn bản của mình, ngay cả khi sau đó tôi đã chỉnh sửa nó bằng Calc.

Tôi đã giải quyết vấn đề của mình bằng cách sao chép và dán trong trình soạn thảo văn bản dữ liệu từ tệp do Calc tạo của tôi sang tệp mới do trình soạn thảo tạo.


1

Tôi đã gặp vấn đề tương tự khi mở CSV được tạo từ một dịch vụ web đã chèn NULL byte vào các tiêu đề trống. Tôi đã làm như sau để xóa tệp:

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

Tuyên bố từ chối trách nhiệm: Hãy lưu ý rằng điều này sẽ ghi đè dữ liệu ban đầu của bạn. Đảm bảo rằng bạn có một bản sao lưu của nó. Bạn đã được cảnh báo!


0

Đối với tất cả những người ghét mã tệp 'rU': Tôi vừa thử mở tệp CSV từ máy Windows trên máy Mac với mã tệp 'rb' và tôi gặp lỗi này từ mô-đun csv:

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

Mở tệp ở chế độ 'rU' hoạt động tốt. Tôi thích chế độ phổ quát-dòng mới - nó giúp tôi tiết kiệm rất nhiều rắc rối.


0

Tôi đã gặp phải điều này khi sử dụng scrapy và tìm nạp một tệp csvfile đã nén mà không có phần mềm trung gian chính xác để giải nén phần thân phản hồi trước khi đưa nó cho csvreader. Do đó, tệp không thực sự là tệp csv và do đó đã line contains NULL bytegây ra lỗi.


0

Bạn đã thử sử dụng gzip.open chưa?

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

Tôi đang cố mở một tệp đã được nén nhưng có phần mở rộng là '.csv' thay vì 'csv.gz'. Lỗi này tiếp tục hiển thị cho đến khi tôi sử dụng gzip.open


-1

Một trường hợp là - Nếu tệp CSV chứa các hàng trống, lỗi này có thể hiển thị. Kiểm tra hàng là cần thiết trước khi chúng tôi tiến hành viết hoặc đọc.

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

Tôi đã giải quyết vấn đề của mình bằng cách thêm kiểm tra này vào mã.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.