Mam obiekt file
, który może ale nie musi być otwarty w trybie uniwersalnym. (Mogę uzyskać dostęp do tego trybu za pomocą file.mode
, jeśli to pomaga).Jak korzystać z prymitywów io (seek, read) w strumieniu pliku, który może być w trybie uniwersalnym?
Chcę zająć się tym plikiem, używając standardowych metod: io
: read
i seek
.
Gdybym otworzyć plik w trybie non-uniwersalnej, wszystko działa dobrze:
In [1]: f = open('example', 'r')
In [2]: f.read()
Out[2]: 'Line1\r\nLine2\r\n' # uhoh, this file has carriage returns
In [3]: f.seek(0)
In [4]: f.read(8)
Out[4]: 'Line1\r\nL'
In [5]: f.seek(-8, 1)
In [6]: f.read(8)
Out[6]: 'Line1\r\nL' # as expected, this is the same as before
In [7]: f.close()
Jednakże, jeśli mogę otworzyć plik w trybie powszechnych, mamy problem:
In [8]: f = open('example', 'rU')
In [9]: f.read()
Out[9]: 'Line1\nLine2\n' # no carriage returns - thanks, 'U'!
In [10]: f.seek(0)
In [11]: f.read(8)
Out[11]: 'Line1\nLi'
In [12]: f.seek(-8, 1)
In [13]: f.read(8)
Out[13]: 'ine1\nLin' # NOT the same output, as what we read as '\n' was *2* bytes
Python interpretuje \r\n
jako \n
i zwraca ciąg o długości 8.
Jednak tworzenie tego ciągu obejmowało czytanie 9 bajtów z pliku.
W rezultacie, przy próbie cofnięcia read
przy użyciu seek
, nie wracamy do miejsca, w którym zaczęliśmy!
Czy istnieje sposób na stwierdzenie, że zużyliśmy 2-bajtowy znak nowej linii lub, jeszcze lepiej, wyłączamy to zachowanie?
Najlepszym mogę wymyślić w tej chwili jest, aby zrobić tell
przed i po odczycie i sprawdź ile rzeczywiście dostał, ale to wydaje się bardzo nieeleganckie.
Tak na marginesie, to wydaje mi się, że takie zachowanie jest rzeczywiście sprzeczne z dokumentacją read
:
In [54]: f.read?
Type: builtin_function_or_method
String Form:<built-in method read of file object at 0x1a35f60>
Docstring:
read([size]) -> read at most size bytes, returned as a string.
If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.
Do mojego czytania, który sugeruje, że co najwyżej rozmiar bajtów powinny być czytać , nie zwrócił.
W szczególności uważam, że prawidłowe semantyka powyższym przykładzie powinno być:
In [11]: f.read(8)
Out[11]: 'Line1\nL' # return a string of length *7*
Am I nieporozumienia dokumentację?
Tryb I/O w trybie tekstowym został stworzony przez diabła w celu udaremnienia schematów rodzaju ludzkiego. Unikaj go jak ognia. – user3553031
To, o co prosisz, nie jest możliwe. Wystarczy otworzyć plik w trybie binarnym i pracować z tym. Lub użyj 'io.open (..., newline = '\ n')', aby wyłączyć uniwersalne znaki nowej linii. – Bakuriu