假设我有一个ASCII文件(称为'test.txt'),如下所示:
A B C D
X Y Z
^ EOF, no CR after the 'Z'...
Run Code Online (Sandbox Code Playgroud)
在Python中,我可以读取最后一个字节(最后一个字符),如下所示:
with open('test.txt', 'r') as f:
f.seek(-1, os.SEEK_END)
ch=f.read(1)
Run Code Online (Sandbox Code Playgroud)
我可以像这样截断最后3个字符:
with open('test.txt', 'r') as f:
f.seek(-3, os.SEEK_END)
f.truncate()
Run Code Online (Sandbox Code Playgroud)
现在假设我有一个以UTF-8编码的第二个文件(称为'test.utf'),其中包含以下单字节和多字节字符:
A B C D
? ? ? ?
Z ?
Run Code Online (Sandbox Code Playgroud)
我知道如何读取整个文件(使用编解码器):
>>> f=codecs.open('/tmp/test.utf', 'r', 'utf-8')
>>> L=f.readlines()
>>> L
[u'A B C D\n', u'\u24b6 \u24b7 \u24b8 \u24b9\n', u'Z \u24cf']
Run Code Online (Sandbox Code Playgroud)
我想我可以使用collections模块中的deque来获取最后N个字符:
>>> from collections import deque
>>> with codecs.open(fn,'r+', encoding) as f:
... last_3=deque(f.read(),3)
>>> last_3
deque([u'Z', u' ', u'\u24cf'], maxlen=3)
Run Code Online (Sandbox Code Playgroud)
所以问题:无论如何(我错过了)在哪里我可以逻辑地通过逻辑字符向后退步UTF-8文件字符而不将整个文件读入内存?使用ASCII很容易; 只需要在文件开头附近寻找一个字节.但是在UTF-8中,?是3个字节(E2 93 8F)并且Z只是一个字节.
回想一下,UTF-8是可变宽度 - 每个字符1到4个字节.除非你从一开始就开始,我认为没有办法知道角色界限是什么......
您可以这样做,但不能作为单个角色.将文件视为字节.
每个UTF-8字符将包含1到4个字节.要读取文件末尾,请读取最后4*n个字节并开始查找字符边界.UTF-8字符的第一个字节具有顶部位模式,0或者11中间的所有其他字节都具有该模式10.只需向后搜索,直到计算出与模式匹配的正确数字.
with open('test.txt', 'rb') as f:
f.seek(-4, os.SEEK_END)
ch=f.read(4)
for i in range(3, -1, -1):
pattern = ord(ch[i]) & 0xc0
if pattern in (0x00, 0x40, 0xc0):
ch = ch[i:]
break
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
266 次 |
| 最近记录: |