python3 读取txt文本最后一行
由字节组成
首先要理解txt文本都是实际由字节组成的,比如对于一个utf-8无BOM编码方式存储的txt文件,如果文件内容为空,那么该txt文件大小为0字节,一个ascii字符占一个字节,一个中文字符占3个字节。
1q;付
比如utf-8无BOM编码方式存储的txt文件,文本内容如上,那么该文件的大小则为6字节。
readlines函数
例子文本内容:
文本编码:utf-8无BOM
代码:
out = open('新建文本文档.txt',encoding = 'utf-8')
lines = out.readlines()
print(lines)
for line in lines:
print(bytes(line,encoding = 'utf-8'))
运行结果:
说明一下,如果最后一行是空行,那么lines列表的最后一个元素则是’333\n’。
可以看出readlines方法是一次读取所有行存入list中,准确的说,是从当前的文件指针读到文本末尾。当然是r模式(读模式)时,指针都是从0开始。
python3自动转换\r\n
python3在使用readline和readlines方法时,会自动将Windows下换行符\r\n变成\n。
如上同样的文本。
运行如下代码:
import os
out = open('新建文本文档.txt',encoding = 'utf-8')
lines = out.readlines()
print(lines)
for line in lines:
print(bytes(line,encoding = 'utf-8'))
out = open('新建文本文档.txt','rb')#b,以二进制形式读取
print(out.read())
filesize = os.path.getsize('新建文本文档.txt')
print(filesize)
运行结果为:
21是文件大小,21字节。如果是从lines列表里数字节大小,是7+4+4+3=18,为什么实际上多了三个字节呢,是因为python3对换行符进行了转换,实际存储的每个换行符还是\r\n。
所以,当你不是b模式下读取文本时,换行符是‘\n’,但当你是b模式读取文件时(且平台是Windows),不管是read函数还是readlines函数,其中的换行符是b‘\r\n’。
seek函数
如上同样的文本。
运行如下代码:
dat_file = open('新建文本文档.txt', 'rb')
dat_file.seek(20, 0)
print(dat_file.tell())
print(dat_file.read())
运行结果为:
如果改为dat_file.seek(21, 0)
,运行结果为:。即读取到的是空。当然改成21以上的数字也是读取为空。
原理:之前提到例子文本大小为21字节,所以dat_file.read()
(假设不移动文件指针)读取到的bytes类别字符串的长度也为21,其索引是0-20。
如上图所示,只有当文件指针在0-20范围时,才可能读到内容。
读取文本最后一行
本文的思想:如果把文件指针移动到靠后的位置,那么只要readlines方法返回的list的长度大于2,那么虽然list第一个元素读取的行可能不完整,但后面的元素读取的行肯定都是完整的了。而且考虑到了最后一行或多行是空行的情况。
代码:
import os
def get_last_line(inputfile):
filesize = os.path.getsize(inputfile)
blocksize = 1024
dat_file = open(inputfile, 'rb')
last_line = b""
lines = []
if filesize > blocksize:
maxseekpoint = (filesize // blocksize)#这里的除法取的是floor
maxseekpoint -= 1
dat_file.seek(maxseekpoint * blocksize)
lines = dat_file.readlines()
while((len(lines)<2) | ((len(lines)>=2)&(lines[1]==b'\r\n'))):#因为在Windows下,所以是b'\r\n'
#如果列表长度小于2,或者虽然长度大于等于2,但第二个元素却还是空行
#如果跳出循环,那么lines长度大于等于2,且第二个元素肯定是完整的行
maxseekpoint -= 1
dat_file.seek(maxseekpoint * blocksize)
lines = dat_file.readlines()
elif filesize:#文件大小不为空
dat_file.seek(0, 0)
lines = dat_file.readlines()
if lines:#列表不为空
for i in range(len(lines)-1,-1,-1):
last_line = lines[i].strip()
if(last_line != b''):
break#已经找到最后一个不是空行的
dat_file.close()
return last_line
#该函数返回的是bytes
last = get_last_line('新建文本文档.txt')
last = last.decode()
print(last)
你也可以通过本文的例子文本来进行测试,并将代码改成blocksize = 3
,然后debug方式查看代码运行过程。