2010-07-15 69 views
17

Tôi biết rằng tôi nên mở tệp nhị phân bằng cách sử dụng "rb" thay vì "r" vì Windows hoạt động khác nhau đối với tệp nhị phân và không nhị phân.Sự khác biệt giữa nhị phân và văn bản I/O trong python trên Windows

Nhưng tôi không hiểu chính xác những gì sẽ xảy ra nếu tôi mở một tệp sai và tại sao sự khác biệt này thậm chí còn cần thiết. Các hệ điều hành khác dường như làm tốt bằng cách xử lý cả hai loại tệp giống nhau.

Trả lời

19

Chế độ này là về việc chuyển đổi kết thúc dòng.

Khi đọc ở chế độ văn bản, kết thúc dòng gốc của nền tảng (\r\n trên Windows) được chuyển đổi thành kết thúc dòng Unix kiểu \n của Python. Khi viết ở chế độ văn bản, điều ngược lại sẽ xảy ra.

Ở chế độ nhị phân, không có chuyển đổi nào được thực hiện.

Các nền tảng khác thường hoạt động tốt mà không cần chuyển đổi, vì chúng lưu trữ kết thúc dòng tự nhiên là \n. (Một ngoại lệ là Mac OS, được sử dụng để sử dụng \r trong những ngày cũ.) Mã dựa vào điều này, tuy nhiên, không phải là di động.

+0

Vì vậy, nếu tôi đọc tệp văn bản Windows với python trên Linux, không có chuyển đổi nào xảy ra và tôi sẽ kết thúc bằng một \ r bổ sung trên mỗi dòng? –

+0

Có. [lorem ipsum] – Thomas

+1

@Fabian: vâng. Ứng dụng của bạn phải biết loại tệp nào cần xử lý. Trong hầu hết các trường hợp, bạn có thể chỉ cần kiểm tra nội dung tệp đã đọc cho các chuỗi "\ r \ n" và thay thế bằng "\ n" bằng cách sử dụng các phương thức chuỗi. – jsbueno

1

Trong Windows, chế độ văn bản sẽ chuyển đổi dòng mới \n thành trả về vận chuyển theo sau là dòng mới \r\n.

Nếu bạn đọc văn bản ở chế độ nhị phân, không có vấn đề gì. Nếu bạn đọc dữ liệu nhị phân trong chế độ văn bản, nó có thể sẽ bị hỏng.

-2

Đối với tệp đọc, không có sự khác biệt. Khi ghi vào các tập tin văn bản Windows sẽ tự động xáo trộn các ngắt dòng của bạn (nó sẽ thêm \r trước khi số của \n). Đó là lý do tại sao bạn nên sử dụng "wb".

+1

-1. Trong nhiều trường hợp, bạn * muốn * ngắt dòng trên Windows. Bao giờ thử đọc một tập tin văn bản Unix trong Notepad? – Thomas

22

Điều này là dành cho các lý do lịch sử (hoặc như tôi muốn nói, kích động). Các chế độ mở tệp được kế thừa từ thư viện stdio C và do đó chúng tôi theo dõi nó.

Đối với Windows, không có sự khác biệt giữa tệp văn bản và tệp nhị phân, giống như trong bất kỳ bản sao Unix nào. Không, ý tôi là! - Có (đã) hệ thống tập tin/hệ điều hành, trong đó tập tin văn bản là con thú hoàn toàn khác nhau từ tập tin đối tượng và như vậy. Trong một số bạn đã phải xác định độ dài tối đa của các dòng trước và các bản ghi kích thước cố định đã được sử dụng ... hóa thạch từ thời điểm các thẻ đục lỗ 80 cột và như vậy. May mắn thay, không phải như vậy trong Unices, Windows và Mac.

Tuy nhiên - tất cả những thứ khác bằng nhau - Unix, Windows và Mac hystorically khác nhau về những ký tự họ sử dụng trong luồng đầu ra để đánh dấu kết thúc của một dòng (hoặc cùng một thứ, như dấu phân cách giữa các dòng). Trong Unix, \ x0A (\ n) được sử dụng. Trong Windows, trình tự của hai ký tự \ x0D \ x0A (\ r \ n) được sử dụng; trên máy Mac - chỉ \ xOD (\ r). Dưới đây là một số manh mối về nguồn gốc của việc sử dụng hai ký hiệu đó - mã ASCII 10 được gọi là Nguồn cấp dữ liệu (LF) và khi được gửi tới teletype, sẽ làm cho nó di chuyển xuống một dòng (Y ++), mà không thay đổi chiều ngang của nó (X) Chức vụ. Mặt sau vận chuyển (CR) - Mặt khác ASCII 13 sẽ làm cho việc vận chuyển in trở về đầu dòng (X = 0) mà không cần cuộn xuống một dòng. Vì vậy, khi gửi đầu ra cho máy in, cả hai \ r và \ n phải được gửi đi, do đó, việc vận chuyển sẽ di chuyển đến đầu của một dòng mới. Bây giờ khi gõ trên bàn phím thiết bị đầu cuối, các nhà khai thác tự nhiên được dự kiến ​​sẽ nhấn một phím và không phải hai cho cuối dòng. Điều đó trên Apple] [là chìa khóa 'Return' (\ r).

Dù sao thì đây là cách mọi thứ được giải quyết.Những người sáng tạo của C đã quan tâm đến tính di động - phần lớn Unix được viết bằng C, không giống như trước đây, khi các hệ điều hành được viết bằng bộ lắp ráp. Vì vậy, họ không muốn đối phó với mỗi nền tảng quirks về văn bản đại diện, vì vậy họ thêm hack ác này vào thư viện I/O của họ tùy thuộc vào nền tảng, đầu vào và đầu ra cho tập tin đó sẽ được "vá" trên bay để chương trình sẽ thấy các dòng mới chính xác, Unix-way - as '\ n' - cho dù đó là '\ r \ n' từ Windows hay '\ r' từ Mac. Vì vậy, các nhà phát triển không cần phải lo lắng về những gì hệ điều hành chương trình chạy, nó vẫn có thể đọc và ghi các tập tin văn bản ở định dạng gốc.

Có một vấn đề, tuy nhiên - không phải tất cả các tệp đều là văn bản, có các định dạng khác và chúng rất nhạy cảm để thay thế một ký tự với một ký tự khác. Vì vậy, họ mặc dù, chúng tôi sẽ gọi những "tệp nhị phân" và chỉ ra rằng để fopen() bằng cách bao gồm 'b' trong chế độ - và điều này sẽ gắn cờ thư viện không thực hiện bất kỳ chuyển đổi hậu trường nào. Và đó là cách nó đã trở thành con đường của nó :)

Vì vậy, để tóm tắt lại, nếu tệp mở bằng 'b' ở chế độ nhị phân, sẽ không có chuyển đổi nào diễn ra. Nếu nó được mở trong chế độ văn bản, tùy thuộc vào nền tảng, một số chuyển đổi của (các) ký tự dòng mới có thể xảy ra - theo hướng nhìn của Unix. Đương nhiên, trên nền tảng Unix không có sự khác biệt giữa đọc/ghi vào "văn bản" hoặc "tệp nhị phân".

+1

Ít nhất là trên Windows XP và Python 2.5.1, một tệp có chứa 0x1A (DOS soft EOF) sẽ bị cắt bớt tại vị trí đó khi được đọc dưới dạng văn bản. Xem ví dụ http://stackoverflow.com/q/8743467/908515 –

+0

@undur_gongor điểm tốt, tôi chắc chắn đó là vốn có trong Python từ C thư viện chuẩn thực hiện trên Windows là tốt. xem http://en.wikipedia.org/wiki/End-of-file vì lý do. trong Unix khi^D được nhấn, trình điều khiển thiết bị đầu cuối trả về 'EOF', là' -1' - của kiểu 'int' và không phải' char'. Không phải như vậy trên Windows, mà không có bản dịch của^Z từ thiết bị đầu cuối - thay vì 'getchar()' thực hiện dịch nó sang EOF khi ở chế độ văn bản –

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