2012-03-10 8 views
38

Co sprawia, że ​​parsowanie pliku tekstowego w trybie "r" jest wygodniejsze niż parsowanie go w trybie "rb"? Zwłaszcza, gdy dany plik tekstowy może zawierać znaki spoza ASCII.Różnica między parsowaniem pliku tekstowego w trybie r i rb

+0

Czy czytasz plik tekstowy lub plik binarny? –

+0

Plik tekstowy. Ale z jakiegokolwiek powodu otrzymuję plik jako strumień bajtów. – MxyL

Odpowiedz

44

Zależy to trochę od wersji Pythona, z której korzystasz. W języku Python 2 obowiązuje Chris Drappier's answer.

W Pythonie 3 jest to inna (i bardziej spójna) historia: w trybie tekstowym ('r'), Python przetworzy plik zgodnie z kodowaniem, który mu podasz (lub, jeśli go nie podasz, zależna od platformy), a read() da ci str. W trybie binarnym ('rb') Python nie zakłada, że ​​plik zawiera rzeczy, które można w rozsądny sposób przeanalizować jako znaki, a read() daje obiekt bytes.

Również w Pythonie 3, uniwersalnych nowymi liniami (przekładaniem między '\n' i platformy określonych konwencji nowej linii, więc nie trzeba się martwić o nich) jest dostępna dla plików w trybie tekstowym na Każda platforma, a nie tylko Windows.

+0

dla py3, czy odczyt w trybie tekstowym automatycznie spróbuje wykryć jaki rodzaj kodowania jest? Wyobrażam sobie, że wykrywanie kodowania jest sporym wyzwaniem dla obiektu z bajtami. – MxyL

+1

@Keikoku Wykrywanie kodowania w oparciu o sam strumień, bez żadnych metadanych, jest niemożliwe - pomyśl o różnych kodowaniach, które są ASCII + używają ósmego bitu dla informacji zamiast parzystości; wszystkie mają 255 ważnych jednobajtowych sekwencji, ale tylko połowa z nich (połowa ASCII) reprezentuje ten sam znak w każdej z nich. Domyślnie Python nie domyślam się, że jest to domyślne kodowanie w całej sesji, pisane 'sys.getdefaultencoding()'. Na mojej instalacji Py3, jego UTF-8, ale nie można na tym polegać. – lvc

19

z documentation:

W Windows, 'b' przyłączoną do trybu otwiera plik w trybie binarnym, więc nie są tryby również jak 'rb', 'WB' i „r + b ". Python w systemie Windows rozróżnia tekst i pliki binarne; znaki końca linii w plikach tekstowych są automatycznie zmieniane nieznacznie, gdy dane są odczytywane lub zapisywane. Ta "zakulisowa" modyfikacja danych pliku jest w porządku dla plików tekstowych ASCII, ale spowoduje to uszkodzenie danych binarnych, takich jak w plikach JPEG lub EXE. Zachowaj ostrożność, aby korzystać z trybu binarnego podczas odczytywania i zapisywania takich plików. W systemie Unix nie zaszkodzi dołączyć "b" do trybu, więc można go używać niezależnie od platformy dla wszystkich plików binarnych.

+0

Więc zasadniczo próby odczytu linii w trybie binarnym są znacznie trudniejsze, ponieważ nie mam gwarancji, że znak EOL to \ n lub \ r \ n czy coś innego? – MxyL

8

Różnica polega na sposobie obsługi końca linii (EOL). Różne systemy operacyjne używają różnych znaków do oznaczania EOL-\n w systemie Unix, \r w wersjach dla komputerów Mac starszych niż OS X, \r\n w systemie Windows. Kiedy plik jest otwierany w trybie tekstowym, po odczytaniu pliku, Python zastępuje znak końca linii odczytywany z pliku tylko z \n. I odwrotnie, np. Gdy spróbujesz napisać \n do pliku otwartego w trybie tekstowym, napisze on specyficzny dla systemu operacyjnego znak EOL. Możesz znaleźć domyślny EOL systemu operacyjnego, sprawdzając numer os.linesep.

Gdy plik jest otwierany w trybie binarnym, nie ma mapowania. To, co czytasz, jest tym, co dostajesz. Pamiętaj, że tryb tekstowy jest trybem domyślnym. Jeśli więc zajmujesz się plikami nietekstowymi (obrazami, wideo itp.), Upewnij się, że otwierasz plik w trybie binarnym, w przeciwnym razie zepsujesz plik, wprowadzając (lub usuwając) kilka bajtów.

Python ma również uniwersalny tryb nowej linii. Kiedy plik jest otwierany w tym trybie, Python odwzorowuje wszystkie znaki: \r, \n i \r\n do \n.

+0

Czy dotyczy to zarówno Pythona 2, jak i Pythona 3? – Agostino

2

Dla wyjaśnienia i odpowiedzieć Agostino's comment/question (nie mam wystarczającej reputacji uwag więc pokrywa się ze mną podając to jako odpowiedź ...):

W Pythonie 2 żadna modyfikacja końca linii nastąpi, ani w tekście ani tryb binarny - jak już wspomniano wcześniej, w Pythonie 2 Chris Drappier's answer ma zastosowanie (proszę zauważyć, że jego łącze w dzisiejszych czasach wskazuje na 3.x docs Python ale Chris' cytowany tekst jest oczywiście od Python 2 input and output tutorial)

Więc nie, to nie prawda, że ​​otwarcie pliku w tekst trybie Pythona 2 na non-Windows ma żadnego końca wiersza modyfikacja:

0 $ cat data.txt 
line1 
line2 
line3 
0 $ file data.txt 
data.txt: ASCII text, with CRLF line terminators 
0 $ python2.7 -c 'f = open("data.txt"); print f.readlines()' 
['line1\r\n', 'line2\r\n', 'line3\r\n'] 
0 $ python2.7 -c 'f = open("data.txt", "r"); print f.readlines()' 
['line1\r\n', 'line2\r\n', 'line3\r\n'] 
0 $ python2.7 -c 'f = open("data.txt", "rb"); print f.readlines()' 

jest jednak możliwe, aby otworzyć plik w trybie nowej linii powszechnej w Pythonie 2, który ma dokładnie wykonywać wymienionego końca linii mod:

0 $ python2.7 -c 'f = open("data.txt", "rU"); print f.readlines()' 
['line1\n', 'line2\n', 'line3\n'] 

(uniwersalny tryb nowalinia specifier jest przestarzała jak Python 3.x)

W Pythonie 3, z drugiej strony, linia platforma specyficzne kończy rozumiem znormalizowane aby podczas czytania pliku w tekście „\ n” tryb "\ n" zostaje przekonwertowany na domyślny koniec bieżącej platformy podczas pisania w trybie tekstowym (oprócz bajtów < -> kodowanie/kodowanie bajtów w trybie tekstowym). Na przykład. czytanie pliku DOS/Win CRLF-line-ended w systemie Linux znormalizuje końce linii do '\ n'.

+0

Otwarta funkcja Python3 ma parametr nowej linii do kontrolowania, jeśli jest to wymagane, https://docs.python.org/3/library/functions.html#open "newline kontroluje sposób działania trybu Newlines (dotyczy tylko tekstu Tryb ten może być Brak, '', '\ n', '\ r' i '\ r \ n' Działa to w następujący sposób: Podczas odczytywania danych wejściowych ze strumienia, jeśli nowa linia jest Brak, uniwersalny tryb nowych linii jest włączone " – Davos

Powiązane problemy