标签:nic utf-8 换行符 red 汉字 补充 图片 初始 切片
对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作
(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
rb: 以字节方式读文件
wb: 以字节方式写文件
ab: 以字节方式追加文件
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,所以不能指定编码
#错误举例 f = open (‘test1.py‘, ‘rb‘, encoding = ‘utf -8‘) data = f.read() print(data) f.close() #执行结果: 报错 f = open (‘test1.py‘, ‘rb‘, encoding = ‘utf-8‘) ValueError: binary mode doesn‘t take an encoding argument
(以b方式打开时,因为读取到的内容是字节类型,所以不能指定编码方式,否则会报错)
#正确 f = open (‘test1.py‘, ‘rb‘) data = f.read() print(data) f.close() #执行结果: b"‘hello‘\r\n‘\xe5\xb0\x8f\xe7\x81\xab\xe9\x94\x85‘\r\n‘666‘"
test1.py中的内容如下:
‘hello‘
‘小火锅‘
‘666‘
分析该程序执行结果:
1. python在windows操作系统下,换行符为在windows操作系统下,换行符为 \r\n
2. ‘字符串’-------encode-------》bytes
bytes---------decode-------》‘字符串’
所以,我们想让执行结果为字符串,可在print时做decode处理
f = open (‘test1.py‘, ‘rb‘) data = f.read() print(data.decode(‘utf-8‘)) f.close() #执行结果: ‘hello‘ ‘小火锅‘ ‘666‘
#错误举例 f = open (‘test1.py‘, ‘wb‘) f.write(‘hello‘) f.close() #执行结果: TypeError: a bytes-like object is required, not ‘str‘ (以b方式写入时需要提供字节类型,所以不能写入字符串类型)
#正确 f = open (‘test1.py‘, ‘wb‘) f.write(bytes(‘hello\n小火锅‘, encoding = ‘utf-8‘ )) f.close()
#举例 f = open (‘test1.py‘, ‘ab‘) f.write(bytes(‘hello\n小火锅\n‘, encoding = ‘utf-8‘ )) f.close()
#举例 f = open (‘test1.py‘, ‘w‘, encoding = ‘GB2312‘) f.close() print(f.encoding) #执行结果: GB2312
#举例 f = open (‘test1.py‘, ‘w‘, encoding = ‘utf-8‘) f.close() print(f.closed) #执行结果: True
补充:文件内光标移动
一: read(3):
1. 文件打开方式为文本模式时,代表读取3个字符
2. 文件打开方式为b模式时,代表读取3个字节
二: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate
test1中的内容
aaa
小火锅
666
#举例 f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘) print(f.tell()) f.readline() print(f.tell()) f.readline() print(f.tell()) f.close() #执行结果: 0 5 16
#结果分析: 第一个tell判断光标位置时候,光标在文件开头,即在位置0 读取了一行之后,光标跑到文件第二行开头,但是在Windows操作系统,换行符为 \r\n,占两个字节,而且tell光标移动以字节为单位,所以光标位置为 5 读取了第二行之后,光标跑到了文件第三行开头,光标经历了三个汉字和换行符,在编码方式为 utf-8 时,走过了3*3+2=11个字节,所以光标位置为 16
#举例 f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘) f.seek(2) #光标从默认位置0开始,往后移动两个字节 data = f.read() print(data) #打印光标后的内容 f.close() #执行结果: a 小火锅 666
如果,我将test1.py的内容改为
小火锅
aaa
666
再次执行上述程序
#报错:UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0x8f in position 0: invalid start byte
原因:一个汉字在utf-8编码方式为3个字节,seek(2)移动两个字节,难道有神奇的功能将汉字劈开嘛,所以肯定会报错啊!
关于seek的一些补充:
seek有三种模式,分别为
举例: f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘) f.seek(3) print(f.tell()) f.seek(9) print(f.tell()) f.close() #执行结果 3 9
f = open (‘test1.py‘, ‘rb‘) f.seek(3,1) print(f.tell()) f.seek(10,1) print(f.tell()) f.close() #执行结果 3 13
f = open (‘test1.py‘, ‘rb‘) f.seek(-3,2) #seek 在模式 2 时,第一个参数为负数 print(f.tell()) print(f.read()) f.close() #执行结果 18 b‘6\r\n‘
任务:应用:打开一个日志文件,并且读取最新日志(核心:倒着读文件内容)
日志文件内容如下:
2018/11/20 aaa 上网听歌
2018/11/20 bbb 上网网购
2018/11/20 ccc 上网学习
#方法一 f = open(‘日志文件‘, ‘rb‘) data = f.readlines() #将日志文件的内容以列表形式读到内存中 print(data[-1].decode(‘utf-8‘)) #以切片方式读取列表中最后一个元素,即文件最后一行内容 #执行结果 2018/11/20 ccc 上网学习
#方法二 f = open(‘日志文件‘, ‘rb‘) for i in f: #文件循环方式 offs = -10 #设置初始偏移量 while True: #设置一个死循环来读取文件的最后一行内容,读取到break f.seek(offs, 2) #seek模式2,光标倒着移动 data = f.readlines() #以列表形式读取光标后的内容 if len(data) > 1: #如果该列表长度大于1,说明光标移动到最后一行之前,最后一行内容已被读出,break,反则最后一行内容还未全部读出,将偏移量扩大,直到独处最后一行全部内容 print(‘文件最后一行:%s‘%(data[-1].decode(‘utf-8‘))) break offs *= 2 #执行结果 文件最后一行:2018/11/20 ccc 上网学习
方法一看着简单,但是方法一需要将日志文件的内容一列表形式全部读到内存中,占用较多内存
方法二的思想就是我用最后一行内容,我倒着读,只关注我想得到的信息
举例: f = open(‘日志文件‘, ‘r+‘,encoding = ‘utf-8‘) data = f.truncate(8) print(data)
注意:
Python小白学习之路(二十)—【打开文件的模式二】【文件的其他操作】
标签:nic utf-8 换行符 red 汉字 补充 图片 初始 切片
原文地址:https://www.cnblogs.com/guoruxin/p/10008904.html