2010-04-09 40 views
10

Tôi có một chương trình Python lưu trữ và ghi dữ liệu vào một tệp. Dữ liệu là dữ liệu nhị phân thô, được lưu trữ nội bộ dưới dạng str. Tôi đang viết nó ra thông qua một bộ giải mã utf-8. Tuy nhiên, tôi nhận được UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 25: character maps to <undefined> trong tệp cp1252.py.Làm cách nào để viết dữ liệu nhị phân thô bằng Python?

Điều này trông giống như Python đang cố gắng diễn giải dữ liệu bằng cách sử dụng trang mã mặc định. Nhưng không phải trang mã mặc định. Đó là lý do tại sao tôi đang sử dụng str, không phải unicode.

Tôi đoán câu hỏi của tôi là:

  • Làm thế nào để đại diện cho dữ liệu nhị phân thô trong bộ nhớ, bằng Python?
  • Khi tôi đang viết dữ liệu nhị phân thô qua codec, làm cách nào để mã hóa/hủy mã hóa?
+1

Bạn nói rằng bạn có dữ liệu thô trong một str, làm cách nào bạn tạo dữ liệu đó ở địa điểm đầu tiên? Tôi giả sử bạn có một nguồn unicode một nơi nào đó, nhưng nó không rõ ràng với tôi nếu bạn đang viết unicode "thô" vào str, hoặc nếu bạn đang đọc nó từ một tập tin (như đối tượng) hoặc ... (Đăng chuỗi ví dụ thể hiện lỗi này sẽ hữu ích!) –

Trả lời

21

LƯU Ý: điều này được viết cho Python 2.x. Không chắc chắn nếu áp dụng cho 3.x.

Việc bạn sử dụng str cho dữ liệu nhị phân thô trong bộ nhớ là chính xác.
[Nếu bạn đang sử dụng Python 2.6+, thậm chí tốt hơn nên sử dụng bytes trong 2.6+ chỉ là bí danh str nhưng thể hiện ý định của bạn tốt hơn và sẽ giúp nếu một ngày bạn chuyển mã sang Python 3.]

Như những lưu ý khác, việc ghi dữ liệu nhị phân qua codec là lạ. Mã ghi là có các mã số unicodekết quả đầu ra byte vào tệp. Bạn đang cố gắng làm ngược lại, do đó sự nhầm lẫn của chúng tôi về ý định của bạn ...

[Và chẩn đoán lỗi của bạn có vẻ chính xác: vì codec mong đợi unicode, Python đang giải mã đường của bạn thành unicode với mã hóa mặc định của hệ thống , cuộn cảm.]

Bạn muốn xem gì trong tệp đầu ra?

  • Nếu tập tin nên chứa dữ liệu nhị phân như nó vốn có:

    Sau đó, bạn không phải gửi nó qua một codec; bạn phải viết nó trực tiếp vào tệp.Một codec mã hóa mọi thứ và chỉ có thể phát ra mã hóa hợp lệ của unicode (trong trường hợp của bạn, hợp lệ UTF-8). Không có đầu vào nào bạn có thể cho nó để làm cho nó phát ra tùy ý chuỗi byte!

    • Nếu bạn cần một hỗn hợp dữ liệu nhị phân UTF-8 và thô, bạn nên mở file trực tiếp, và intermix viết của some_data với some_text.encode('utf8') ...

    Lưu ý tuy nhiên đó trộn UTF-8 với dữ liệu tùy ý thô là rất thiết kế kém, bởi vì các tệp như vậy rất bất tiện để xử lý với! Các công cụ hiểu unicode sẽ bị nghẹt thở trên dữ liệu nhị phân , khiến bạn không thuận tiện để xem ngay cả (hãy để một mình sửa đổi) tệp.

  • Nếu bạn muốn có một đại diện thân thiện của byte tùy ý trong unicode:

    đèo data.encode('base64') đến codec. Base64 chỉ tạo ra ascii sạch (chữ cái, số và dấu chấm câu nhỏ) để có thể nhúng rõ ràng vào bất cứ thứ gì, nó rõ ràng trông giống như dữ liệu nhị phân và nhỏ gọn hợp lý (trên 33% trên đầu).

    P.S. bạn có thể lưu ý rằng data.encode('base64') là lạ.

    • .encode() là nghĩa vụ phải chăm unicode nhưng tôi cho nó một chuỗi ?! Python có một số codec giả để chuyển đổi str-> str như 'base64' và 'zlib'.

    • .encode() luôn trả về một đường nhưng bạn sẽ chuyển nó vào codec mong đợi unicode ?! Trong trường hợp này nó sẽ chỉ chứa sạch ascii, vì vậy nó không quan trọng. Bạn có thể viết rõ ràng data.encode('base64').encode('utf8') nếu điều đó làm cho bạn cảm thấy tốt hơn .

  • Nếu bạn cần một 1: lập bản đồ 1 từ byte tùy ý để Unicode:

    đèo data.decode('latin1') đến codec. latin1 bản đồ byte 0-255 để unicode ký tự 0-255, đó là kinda thanh lịch.

    Codec sẽ mã hóa các ký tự của bạn - 128-255 là được mã hóa là 2 hoặc 3 byte trong UTF-8 (đáng ngạc nhiên, chi phí trung bình là 50%, nhiều hơn base64!). Điều này khá giết "sang trọng" của việc lập bản đồ 1: 1.

    Lưu ý rằng các ký tự unicode 0-255 bao gồm các ký tự vô hình vô hình/kiểm soát (dòng mới, formfeed, dấu gạch nối mềm, v.v.) làm cho dữ liệu nhị phân của bạn gây phiền nhiễu khi xem trong trình chỉnh sửa văn bản.

    Xem xét những hạn chế này, Tôi không khuyến nghị latin1 trừ khi bạn hiểu chính xác lý do bạn muốn.
    Tôi chỉ đề cập đến nó như là mã hóa "tự nhiên" khác mà lò xo để tâm trí.

0

Bạn thường không nên sử dụng codec với str, ngoại trừ để biến chúng thành unicode s. Có lẽ bạn nên xem xét sử dụng codec latin-1 nếu bạn cho rằng bạn muốn dữ liệu "thô" trong unicodes của mình.

+0

Tôi không muốn dữ liệu "thô" trong unicodes của mình. –

+0

Vậy tại sao bạn sử dụng codec? –

+0

Tôi đang ghi dữ liệu nhị phân thô vào một tệp văn bản, cùng với một số chuỗi unicode. Khi tôi cố gắng viết dữ liệu nhị phân thô (mà tôi đã lưu trữ trong định dạng utf-8) vào một codec utf-8, tôi nhận được lỗi cp1252. –

0

Đối với câu hỏi đầu tiên của bạn: bằng Python, chuỗi thông thường (ví dụ, không phải chuỗi unicode) là dữ liệu nhị phân. Nếu bạn muốn viết các chuỗi unicode và dữ liệu nhị phân, biến các chuỗi unicode vào dữ liệu nhị phân và đặt chúng lại với nhau:

# encode the unicode string as a string 
bytes = unicodeString.encode('utf-8') 
# add it to the other string 
raw_data += bytes 
# write it all to a file 
yourFile.write(raw_data) 

Đối với câu hỏi thứ hai của bạn: bạn write() các dữ liệu thô; sau đó, khi bạn đọc nó, bạn làm như vậy như sau:

import codecs 
yourFile = codecs.open("yourFileName", "r", "utf-8") 
# and now just use yourFile.read() to read it 
+0

Như tôi đã đề cập, tôi * có * một chuỗi thông thường. –

+0

Và làm 'yourFile.write (regular_string)' cung cấp cho bạn lỗi? Bạn không cần phải mã hóa thêm một chuỗi thông thường; như tôi đã nói, nó đã là byte thô. –

+0

@ Chris: Bạn có đang làm điều gì đó ngớ ngẩn như sử dụng Python 3, có lẽ không? – SamB

Các vấn đề liên quan