009.Python之with管理与文件操作的其他方法

一、文件操作模式补充

(一)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()

# 以上程序,在第一次读操作的时候,已经将文件内容全部读取到,紧接着又进行了依次读取操作,但是这次读取内容是什么呢?实际是空的,因为第一次读取后,指针在文件的末尾,而文件未关闭或进行其他指针移动操作,所以指针位置不变,再次读取,将不会有任何内容被读出。
原文地址:https://www.cnblogs.com/huluhuluwa/p/13095558.html