目录
一、文件操作模式补充
(一)with上下文管理
1.with是什么
with关键字是python提供给我们的一个功能,用于帮助管理我们计算机的资源,提高计算机资源的利用效率,最终提高程序的运行效率。
2.为什么要用with
我们进行文件操作的时候,打开一个文件包含两部分资源,应用程序的变量f和操作系统打开的文件。在操作完毕一个文件的时候,必须把与该文件相关的这两部分资源全部回收,回收方法为:
1、f.close() #回收操作系统打开的文件资源
2、del f #回收应用程序级的变量
其中del f 一定要发生在f.close()之后,否则就会导致操作系统打开的文件无法关闭,白白占用资源,而python自动的垃圾回收机制决定了我们无序考虑del f ,这就要求我们,在操作完毕文件后,一定要记住f.close()操作。但是这个操作常常有人会忘记,考虑到这一点,python提供了with关键字来帮我们管理上下文,解决忘记关闭 文件句柄f 的问题。
3.怎么用with
我们之前使用的文件操作方法是:
1) 打开文件,由应用程序向操作系统发起系统调用open(...),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f
f=open('a.txt','r',encoding='utf-8') # 默认打开模式就为r
2) 调用文件对象下的读/写方法,会被操作系统转换为读/写硬盘的操作
data=f.read()
3) 向操作系统发起关闭文件的请求,回收系统资源
f.close()
使用了with之后,我们就可以简化掉第三步,并为我们提供了同时打开多个文件的功能:
1) 在执行完子代码块后,with 会自动执行f.close():
with open('a.txt','w') as f:
pass
2) 可用用with同时打开多个文件,用逗号分隔开即可:
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
data = read_f.read()
write_f.write(data)
(二)b模式
1.t模式与b模式比较
(1)t模式只能读取文本文件
# 操作文件过程中,切记编码的问题!
with open('a.txt',mode='rt') as f: # 'a.txt'内容:你好呀
哈哈哈
hello
data=f.read()
print(data) # 报错 UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 8: illegal multibyte sequence 所以我们需要注意字符编码的问题,指定编码类型!!
print(type(data))
with open('a.txt',mode='rt') as f: # 'a.txt'内容:hello
data=f.read()
print(data) # hello
print(type(data)) # <class 'str'> 我们的文本文件读取,是以字符串为单位的。
with open('a.jpg',mode='rt',encoding='utf-8') as f:
data=f.read()
print(data) # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
# 使用t模式读取图片文件,会报错,并提示需要使用b模式读取
# 图片<---------jpg-------二进制数
# 字符<---------utf-8-------二进制数
(2)b模式能用于读取所有文件
with open('a.jpg',mode='rb') as f:
data=f.read()
print(data) # b'xff... 一大串经过python修改过的二级制数据
print(type(data)) # <class 'bytes'>
with open('a.jpg', mode='rb') as f:
data = f.read()
print(data.decode("utf-8")) # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
2.编写copy工具的两种方式
方式一:一次性读取,如果文件过大,可能会造成内存溢出
with open('a.jpg', mode='rb') as src_f,
open('b.jpg', mode='wb') as dst_f:
data = src_f.read()
print(data) # b模式二进制数
dst_f.write(data)
方式二:推荐使用,每次只读一行内容,资源压力小
with open('a.jpg', mode='rb') as src_f,
open('b.jpg', mode='wb') as dst_f:
for line in src_f: # line=文件中的1行内容
dst_f.write(line)
3.使用b模式copy文本文件
1) 使用b模式copy文本文件
with open('b.txt', mode='wb') as f:
user = "张三"
res=user.encode('utf-8')
f.write(res)
2) 使用t模式copy文本文件
with open('b.txt', mode='wt', encoding="utf-8") as f:
user = "张三"
f.write(user)
# 使用b模式虽然可以拷贝文本文件,但是操作过于复杂,最好直接使用t模式
(三)+模式(了解)
# r+ w+ a+ :可读可写
#在平时工作中,我们只单纯使用r/w/a,要么只读,要么只写,一般不用可读可写的模式
(四)文件操作的其他方法
1.readlines()
每次读取一行,并写入列表
with open('b.txt', mode='rt', encoding='utf-8') as f:
l = []
for line in f:
l.append(line)
print(l) # ['111
'] / ['111
', '222
'] / ['111
', '222
', '333
'] / ['111
', '222
', '333
', '444
']
l = f.readlines() # 以上三行代码的操作,可以使用一行完成,直接输出结果
print(l) # ['111
', '222
', '333
', '444
']
2.writelines()
循环目标数据,按照单个元素循环写入
with open('b.txt', mode='wt', encoding='utf-8') as f:
1) 方式1
f.write("1111
2222
333
")
2) 方式2
lines=["1111
","222
","333
"]
for line in lines:
f.write(line)
3) 方式3
lines=["1111
","222
","333
"]
f.writelines(lines)
# 以上三种方法都可以实现将这组数据写入文件,使用第三种最方便。
3.name
f.name 是获取文件的路径
with open(r'b.txt', mode='wt', encoding='utf-8') as f:
print(f.name) # b.txt 获取的是文件的路径
4.flush()
# 强制刷新
with open(r'b.txt', mode='wt', encoding='utf-8') as f:
f.write('哈哈哈
')
f.flush() # 不使用flush的话,操作系统会按照系统规则,攒一波数据批量写入,但是使用flush的话,就可以强制写入硬盘,但不推荐使用,除非必要。
(五)其他补充知识
1.补充:字符编码知识
user = "张三"
# 编码操作:
# 字符串===utf-8===》bytes
res=user.encode("utf-8")
print(res) # b'xe5xbcxa0xe4xb8x89'
print(type(res)) # <class 'bytes'>
# 基于网络发送数据(res)
# 解码操作:
# t模式是帮我们解码了
# 字符<---------utf-8-------二进制数
# bytes====》utf-8=====》字符串
print(res.decode("utf-8")) # 张三
2.a模式应用场景:日志的切割
我们在维护程序的时候,若不对日志文件进行管理,日志就会无线增大,所以我们常常在日志文件达到一定大小的时候,对日志文件进行切割。具体做法是将原日志文件重新命名,增加上时间标识,然后程序在找不到日志文件的情况下,会重新创建一个新的日志文件。
3.rt模式下的理解易错点
f=open('今日内容.txt',mode='rt',encoding='utf-8')
print('第一次读'.center(50,'='))
res1=f.read()
print(res1)
print('第二次读'.center(50,'='))
res2=f.read()
print(res2)
f.close()
# 以上程序,在第一次读操作的时候,已经将文件内容全部读取到,紧接着又进行了依次读取操作,但是这次读取内容是什么呢?实际是空的,因为第一次读取后,指针在文件的末尾,而文件未关闭或进行其他指针移动操作,所以指针位置不变,再次读取,将不会有任何内容被读出。