字符串存储到硬盘上的编码流程
字符串——encode——bytes
将bytes形式转化成字符串
bytes——decode——字符串
文件处理模式b模式 rb:以读的模式,以字节的方式去读
f = open(‘test11.py‘,’rb‘, encoding=’utf-8') 会报错
因为你已经告诉程序使用rb模式读取,就不应该再指定encoding编码,所以b模式不能指定编码
字节是以二进制形式为单位
open()是一个函数,完成一个特定的功能,打开文件
f = open(‘test11.py’,‘rb')
data = f.read()
print(data) ---------------------显示的是字符串的原生模式, 没有实际操作,但是在字符串模式中就会以回车形式显示
print(data.decode('utf-8'))
结果:’hello 2222222 33333 44444'
在window平台中回车是
在linux平台中回车是
f = open('test222.py', 'wb')
f.write(bytes('1111 ', encoding='utf-8') 等同于 f.write(‘海绵宝宝’,encode(‘utf-8’))
f = open ('test22.py', 'ab') 其中‘ab’不代表在最后一行写,应该是在文件光标最后一个位置里写。
f.write('海绵宝宝‘, encode(’utf-8‘))
问题一:为什么用二进制保存
二进制可以跨平台传输,在window中比较有用,linux默认是以bytes
x = ’hello‘
b = bytes(x.encoding='utf-8') 等同于 x.encode('utf-8')
class(x) ——str
class(b) ——bytes
查看类型class
文件使用的其他方法:
close 关闭
closed 判断是否关闭——布尔值,文件关闭返回的是True
encoding 显示用什么编码,就取什么编码打开 如果不知道原文件的编码就会乱码
errors 关于编码的报错
flush 刷新——将文件内容从内存刷到硬盘中
f.flush() 运行文件时,数据是保存在内存里面,pycharm会自动帮你保存(过几秒),所以pycharm是演示不出来,要在终端中演示
isatty ——是不是终端设备
name ——文件名
seek ——控制光标移动
seek(3)从头开始算,将光标移动到第三个字节
文件内光标移动:
注意,read(3)代表是读取3个字符,其余的文件内光标移动都是以字节为单位,如seek,tell,read,truncate
f.seek(1)——有可能会报错
因为’你‘是由三个字节组成(utf-8)组成,seek(1) 你 1|23 会报错为无效位置
seekable
tell ——显示光标所在位置
truncate ——文件截断(要在写的模式什么都行,就是w+不行,会覆盖)
f.truncate(10):从开头开始算,将文件保留从0-10个字节,文件必须以写的方式打开,但是w和w+除外
readlines()读一行,读到一行
f =open('b.txt','r', encoding='utf-8', newline=' ')
其中encoding不指定会默认找操作系统编码,newline是读取文件中真正的换行符号
print(f.readlines())
结果:['你好’ ', 'helloaaaa'] 如果没有newline=' ',则没有 ,只有
seek有三种模式
第一种模式(不用指定‘rb’):f.seek(10,0) 其中0是默认参数,从开始作为你的相对位置
第二种模式(相对模式):f.seek(3, 1) 其中1是表示使用第二个模式,表示采用相对位置,相对于上一次位置
第三种模式(文件末尾seek,倒着读就倒着seek):f.seek(10,2)----错误,倒着seek就应该以负数形式。使用在日志文件中使用
写日志时一定要写上时间,分析当前最近的日志,最新的通常在文件最后一行
seek是按照字节方式seek,所以seek的时候要以‘rb’方式去操作(seek的二和三模式要)
循环文件的推荐方法
for i in f: print(i)
读文件最后一行推荐方法(文件内容几个g)
f = open('日志文件','rb') for i in f: offs = -10 while True: f.seek(offs, 2) data = f.readlines() if len(data)>1: print(‘文件的最后一行是%s’%(data[1](‘utf-8'))) break offs *= 2 日志文件读最后一行
不推荐用法
f = open('日志文件’,‘rb’) data = f.readlines() #这样会加载文件的所有内容 print(data[-1].decode('utf-8'))
迭代器和递归
迭代器协议是指:
1.对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个stoplteration异常,以终止迭代(只能往后走,不能往前退。可以理解成儿子不可能生父亲)
2.可迭代对象实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法
3.协议是一种约定,可迭代对象实现了迭代器协议,python内部工具,(如for循环,sum, min, max,函数等)使用迭代器协议访问对象
迭代器的好处:用的时候才拿,内存占用率低,用完就回收。
python中强大的for循环机制
for循环的本质:循环所有对象,全都是使用迭代器协议
准确来说(字符串, 列表, 元组, 字典, 集合, 文件对象)这些都不是可迭代对象
只有通过for循环式,调用了它们内部的___iter__方式
把它们变成了可迭代对象
然后for循环调用可迭代对象的__next__方法去取值
而且for循环会捕捉stoplteration异常,以终止迭代
不用for循环,用while循环进行遍历适用有序,--------不适用于无序(字典和集合)
index = 0
while index<len(l):
print( l [index] )
l = [1, 2, 3]
for i in l : 这里会进行两个步骤 1.先调用___iter__放到 l 的地方(转化), 2.进行 l.__next__() (调用next)
print(i)
next 内置函数.
next是python系统里的内置函数,调用__iter__和___next__()
迭代器就是可迭代对象
生成器 :一种数据类型,自动实现了迭代器协议 (generator object 生成器对象)
在python里
生成器函数
生成器表达式
return——执行就退出
yield——有点类似return值,执行完不会马上结束,可以返回多个值,即好像可以return多次一样
def test():
yield 1 -------|
yield 2 ---------------实现生成器协议
yield 3 -------|
g = test()
print(‘来自函数’,g) ------打印的是生成器
print(g.__next__())
三元表达式,注意不存在四元表达式
name=‘wwe’
#name =‘海绵宝宝’
res = ‘巴基斯坦炸弹摔’ if name == ‘wwe’ else ‘天真可爱’
如果是True,返回‘巴基斯坦炸弹摔’
如果是False,返回‘天真可爱’
print(res)
列表解析——生成一个列表,会放到内存,占用内存。如果数据太大就不推荐使用这个方法
egg_list = [ ]
for i in range(10):
egg_list.append('鸡蛋%s‘ %i) ==等同于== l = ['鸡蛋%s’%i for i in range(10)]
print(egg_list)
l = ['鸡蛋%s’%i for i in range(10)]--------方括号
laomuji = ('鸡蛋%s‘%i for i in range(10))------生成器表达式(圆括号)
print(laomuji) -----打印的是生成器
下蛋 print(laomuji.__next__()) 等同于 print(next(laomuji) )
还可以:
l = [ '鸡蛋%s’%i for i in range(10)if i >5 ]
其中:
一元:for i in range(10)
二元: ‘鸡蛋%s’%i
三元:if i > 5 --------后面不能再写else,写了就是四元,就会报错。
顺序为 三元成立,着传给一元,一元成立传给二元打印