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方式查看代码运行过程。

posted @ 2018-06-10 16:59  allMayMight  阅读(922)  评论(0编辑  收藏  举报