1.文件处理流程

a.打开文件,得到文件句柄并赋值给一个变量

b.通过句柄对文件进行操作

c.关闭文件

f = open('123', encoding='utf8') #pycharm默认将文件以utf8格式编码到硬盘上,虽然python3的编码是utf8,
# 但open函数会去检索当前系统的编码,
# 当前系统是windows,所以open打开文件时用gbk解码,open加的是文件的绝对路径
data = f.read()
print(data)
f.close()

2.文件打开模式

a.r  读操作 

f = open('123', encoding='utf8')
print('第1行', f.readline())#readline一行一行读,读的行数超出文本行数会显示空
print('第2行', f.readline(), end='')#end=''可以去掉换行
print('第3行', f.readline())
print('第4行', f.readline())
print('第5行', f.readline())
print('第6行', f.readline())
f = open('123', encoding='utf8')
data = f.read()
print('第1行', f.readline())#read和readline组合,readline会得到空,因为 read是 读取全部,已经读到文件最后了
f = open('123', encoding='utf8')
data = f.readlines()
print(data)#返回值是所有行以列表形式呈现

b.w写操作

f = open('123', 'w', encoding='utf8')#w模式:文件不存在,会自动新建一个新文件;文件存在,会清空掉文件内容再做操作
f.write('11111111\n')#write的参数必须是字符串
f.write('22222222\n')
f.write('333\n444\n555\n')
print(f.writable())
f.writelines(['666\n', '777\n'])#传入的参数需为列表
f.close()

c.a追加操作:在文件最后一个位置追加

f = open('123', 'a', encoding = 'utf8')
f.write('最后啦')
f.close

 d.r+可读可写

f = open('123', 'r+', encoding='utf8')
data = f.read()
print(data)
f.write('123')#默认从光标起始位置覆盖

 文件无修改,文件在硬盘上以二进制形式存储,修改文件实际是覆盖操作,修改文件步骤:

通过软件打开文件(将文件的内容从硬盘加载到内存),在内存中可以修改文件内容,改完后由软件保存(将文件内容覆盖回去)

模拟文件修改过程:

src_f = open('123', 'r', encoding='utf8')
data = src_f.readlines()
src_f.close

dst_f = open('123', 'w', encoding='utf8')
# dst_f.writelines(data)
dst_f.write(data[0])
dst_f.close

 with +open中with表示close的意思

with open('a.txt', 'w') as f:
f.write('1111\n')
with open('123', 'r', encoding='utf8') as src_f, \
open('123_new', 'w', encoding='utf8') as dst_f:
data = src_f.read()
dst_f.write(data)

 e.文件处理模式b模式 

f = open('123', 'rb', encoding='utf8')#b的方式不能指定编码
f = open('123', 'rb')
data = f.read()
print(data)#windows中的换行是\r\n,linux中的换行是\n
#字符串 encode 二进制bytes
#二进制bytes decode 字符串
print(data.decode('utf8'))
f.close
f = open('123', 'wb')
f.write(bytes('gggg\n', encoding='utf8'))#编码方式一bytes函数
f.write('啦啦'.encode('utf8'))#编码方式二encode函数
f = open('123', 'ab')
f.write(bytes('gggg\n', encoding='utf8'))#编码方式一bytes函数
f.write('啦啦'.encode('utf8'))#编码方式二encode函数

b模式可以打开不同文件类型(视频、图片、文本等),不带b模式默认以文本模式打开

b模式可以跨平台

b模式对Linux系统没有用,因为Linux默认就是以二进制处理的

f.文件操作的其他方法

closed 判断文件是否是关闭状态

f.closed #文件如果关闭则返回True

encoding 取的是文件打开的编码,跟原文件以什么编码方式存到硬盘上没有关系

f.encoding #查看使用open打开文件的编码

flush 

 f.flush() #讲文件内容从内存刷到硬盘

tell当前光标位置

 f.tell() #查看文件处理当前的光标位置
f = open('a.txt', 'r', encoding='gbk')
print(f.closed)
print(f.encoding)
print(f.tell())
f.readline()
print(f.tell())

 newline读取文件中真正的换行符号

f = open('a.txt', 'r', encoding='utf8', newline='')#如果不加newline,读出的换行符号为\n,这是pycharm默认处理的结果
print(f.readlines())

read方法处理文件时按字符读取,其余的文件内光标移动都是以字节为单位

seek

f.seek(3) #从开头开始算,将光标移动到第三个字节

truncate截取

 f.truncate(10) #从开头开始算,将文件只保留从0-10个字节的内容,文件必须以写方式打开,但是w和w+除外,因为它们一打开文件,内容都被清空了

 seek的三种模式:

a.0模式:从头开始seek

f=open('seek.txt', 'r', encoding='utf8')
print(f.tell())#刚打开文件,文件的光标就在0的位置
f.seek(10)
print(f.tell())#seek到哪,打印就到哪
f.seek(3, 0)#默认都是从0开始seek
print(f.tell())

 b.1模式:从上次光标的位置开始seek

f=open('seek.txt', 'rb')#seek0模式不需要以b的方式打开,其他模式需要以b的方式打开
print(f.tell())#刚打开文件,文件的光标就在0的位置
f.seek(10, 1)
print(f.tell())
f.seek(3, 1)
print(f.tell())

 c.2模式:从文件末尾开始seek

f=open('seek.txt', 'rb')#seek0模式不需要以b的方式打开,其他模式需要以b的方式打开
print(f.tell())#刚打开文件,文件的光标就在0的位置
f.seek(-5, 2)#倒着seek,要以负数的方式显示
print(f.read())

 需求 :读取文件最后一行 

方法1:

f = open('seek.txt', 'rb')
data = f.readlines()#非常占内存
print(data[-1].decode('utf8'))

 方法2:

f = open('seek.txt', 'rb')
for i in f:#循环文件的推荐方式,省内存,一条一条的取,不符合就弃掉
offs = -10 #定义偏移量
while True:
f.seek(offs, 2)
data = f.readlines()
if len(data) > 1:
print('文件的最后一行是%s' %(data[-1].decode('utf8')))
break
offs*=2

3.迭代器协议和for循环工作机制

a.递归:自己调自己

b.迭代:被for循环遍历

c.迭代器协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代(只能往后走不能往前退)

d.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个_iter_()方法)

e.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(for循环,sum,min,max函数)使用迭代器协议访问对象

f.for 循环的本质:循环所有对象,全都是使用迭代器协议

g.字符串、列表、元组、字典、集合、文件对象都不是可迭代对象,只不过在for循环时,调用了它们内部的_iter_(或iter())方法,把它们变成了可迭代对象

然后for循环调用了可迭代对象的_next_方法去取值,而且for循环会捕捉StopIteration异常,以终止迭代 

x = 'hello'
iter_test = x.__iter__()
print(iter_test)
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())#会报错

h. for 循环可以遍历列表,while循环也可以遍历列表

l = [1, 2, 3]
index = 0
while index < len(l):
print(l[index])
index += 1

i.为什么要有for循环?

序列类型字符串、元组、列表都有下标,用while循环可以遍历;但非序列类型字典、集合、文件没办法用while循环来做,for循环基于迭代器协议提供了一个统一的可以遍历所有对象的方法

s = {1, 2, 3}
iter_s = s.__iter__()
print(iter_s.__next__())
dic = {'a': 1, 'b': 2}
iter_d = dic.__iter__()
print(iter_d.__next__())#返回值是key值

j.用while模拟for循环做的事情

l = [1, 2, 3, 4, 5]
iter_l = l.__iter__()
while True:
try:
print(iter_l.__next__())
except StopIteration:
print('迭代完成了')#for循环不打印这一句
break

k.next()函数

l = ['father',  'son', 'grandson', 'grandgrandson']#占内存方式 :所有内容都放到内存里
iter_l = l.__iter__()#占内存方式:迭代器对象
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(iter_l.__next__())
print(next(iter_l))#next(python内置函数)相当于调用iter_l.__next__()(数据类型内置的)

4.生成器 

a.生成器定义

可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象

b.生成器分类及在python中的表现形式(pyhton有两种不同的方式提供生成器)

1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行

def test():
yield 1
yield 2
yield 3
g = test()
print(g)

2.生成器表达式:

hen = ('鸡蛋%s' %i for i in range(10))#生成器表达式直接实现迭代器协议,节省内存
print(hen)
print(hen.__next__())
print(next(hen))
print(hen.__next__())
print(next(hen))

c.三元表达式/三元运算

name = 'cyx'
res = 'gb' if name == 'cyx' else 'gg'#三元表达式
print(res)

d.列表解析

l = ['a' for i in range(10)]#循环十次,依次把a放到这个列表中
print(l)

需求:用一行代码代替以下代码

egg_list = []
for i in range(10):
egg_list.append('鸡蛋%s' %i)
print(egg_list)
l = ['鸡蛋%s' %i for i in range(10)]
print(l)
l = ['鸡蛋%s' %i for i in range(10) if i > 5]#列表解析里可以用三元表达式
print(l)
l = ['鸡蛋%s' %i for i in range(10) if i > 5 else i]#没有四元表达式,可以有两元

列表解析的缺点:生成的就是列表,会占内存

总结:把列表解析的[]换成()得到的就是生成器表达式

列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

python不但使用迭代器协议使for循环变得更加通用,大部分内置函数也是使用迭代器协议访问对象的

print(sum(i**2 for i in range(5)))

 补充:生成器只能遍历一次

def test():
for i in range(4):
yield i
t = test()
for i in t:
print(i)
t1 = (i for i in t)
print(list(t1))#生成器只能遍历一次,所以输出结果为[]

 

 

 

 

 

 

 

 

 


posted on 2018-04-29 22:41  吃猫粮的狗  阅读(152)  评论(0编辑  收藏  举报