2010-06-21 65 views
17

Tôi không thể tạo tệp csv utf-8 bằng Python.Tạo tệp csv utf-8 trong Python

Tôi đang cố gắng để đọc nó tài liệu, và trong examples section, nó nói:

For all other encodings the following UnicodeReader and UnicodeWriter classes can be used. They take an additional encoding parameter in their constructor and make sure that the data passes the real reader or writer encoded as UTF-8:

Ok. Vì vậy, tôi có mã này:

values = (unicode("Ñ", "utf-8"), unicode("é", "utf-8")) 
f = codecs.open('eggs.csv', 'w', encoding="utf-8") 
writer = UnicodeWriter(f) 
writer.writerow(values) 

Và tôi tiếp tục nhận được lỗi này:

line 159, in writerow 
    self.stream.write(data) 
    File "/usr/lib/python2.6/codecs.py", line 686, in write 
    return self.writer.write(data) 
    File "/usr/lib/python2.6/codecs.py", line 351, in write 
    data, consumed = self.encode(object, self.errors) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 22: ordinal not in range(128) 

Ai đó có thể xin vui lòng cho tôi một ánh sáng để tôi có thể hiểu cái quái gì tôi làm sai kể từ khi tôi đặt tất cả các mã hóa ở khắp mọi nơi trước khi gọi lớp UnicodeWriter?

class UnicodeWriter: 
    """ 
    A CSV writer which will write rows to CSV file "f", 
    which is encoded in the given encoding. 
    """ 

    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): 
     # Redirect output to a queue 
     self.queue = cStringIO.StringIO() 
     self.writer = csv.writer(self.queue, dialect=dialect, **kwds) 
     self.stream = f 
     self.encoder = codecs.getincrementalencoder(encoding)() 

    def writerow(self, row): 
     self.writer.writerow([s.encode("utf-8") for s in row]) 
     # Fetch UTF-8 output from the queue ... 
     data = self.queue.getvalue() 
     data = data.decode("utf-8") 
     # ... and reencode it into the target encoding 
     data = self.encoder.encode(data) 
     # write to the target stream 
     self.stream.write(data) 
     # empty queue 
     self.queue.truncate(0) 

    def writerows(self, rows): 
     for row in rows: 
      self.writerow(row) 
+0

Nó seens vấn đề là với codecs.open. Khi tôi gỡ bỏ nó và chỉ sử dụng mở, nó hoạt động. Tại sao? –

Trả lời

14

Bạn không phải sử dụng codecs.open; UnicodeWriter lấy đầu vào Unicode và xử lý mọi thứ thành mã UTF-8. Khi UnicodeWriter ghi vào bộ xử lý tệp mà bạn đã chuyển đến, mọi thứ đã được mã hóa UTF-8 (do đó nó hoạt động với một tệp bình thường mà bạn đã mở bằng open).

Bằng cách sử dụng codecs.open, về cơ bản, bạn chuyển đổi các đối tượng Unicode thành chuỗi UTF-8 trong UnicodeWriter, sau đó thử mã hóa lại các chuỗi này thành UTF-8 một lần nữa.

+0

Làm thế nào chính xác tôi đã cố gắng mã hóa hai lần, kể từ khi tôi chỉ cần mở một đối tượng tập tin? Không phải codec.open vừa mở một luồng đối tượng tệp cho biết mã hóa của nó có phải là mã hóa không? –

+2

Theo tài liệu của 'codecs.open':" Mở một tệp được mã hóa bằng cách sử dụng chế độ đã cho và trả về một phiên bản gói * cung cấp mã hóa/giải mã trong suốt *. ". Nói cách khác, nếu bạn mở một tập tin để viết với 'codec.mở', nó sẽ mã hóa tất cả mọi thứ bạn viết vào nó thành UTF-8 trước tiên. –

+0

Tôi nghĩ "cung cấp mã hóa/giải mã trong suốt" quá chủ quan. Tôi nghĩ rằng nếu tôi cần hiểu thêm thì tôi chỉ cần đọc nguồn. –

0

Bạn không cần phải "mã hóa kép" mọi thứ.

Ứng dụng của bạn sẽ hoạt động hoàn toàn bằng Unicode.

Chỉ mã hóa của bạn trong codecs.open để ghi byte UTF-8 vào tệp bên ngoài. Không mã hóa khác trong ứng dụng của bạn.

+1

Mô-đun Csv không hoạt động với unicode. Để làm cho mã của tôi hoạt động, tôi phải xóa chính xác codecs.open. –

+0

Nếu CSV không hoạt động với unicode thì bạn không thể sử dụng nó để tạo UTF-8, trừ khi bạn muốn viết bộ mã hóa UTF-8 của riêng bạn. –

1

Như bạn đã tìm ra nó hoạt động nếu bạn sử dụng đồng bằng mở.

Lý do cho việc này là bạn đã cố gắng mã hóa UTF-8 hai lần. Một lần trong

f = codecs.open('eggs.csv', 'w', encoding="utf-8") 

và sau đó trong UnicodeWriter.writeRow

# ... and reencode it into the target encoding 
data = self.encoder.encode(data) 

Để kiểm tra xem công trình này sử dụng mã ban đầu của bạn và outcomment dòng đó.

Greetz