文件的高级应用
一、可读、可写(不经常用到,了解即可)
- r+t:可读、可写 r+
- w+t:可写、可读 w+
- a+t:可追加、可读 a+
# r+ r+w
with open(r'text.txt',mode='r+',encoding='utf-8') as f:
print(f.readable())
print(f.writable())
f.write('嘿嘿嘿')
True
True
# w+t w+t
with open(r'text.txt',mode='w+',encoding='utf-8') as f:
print(f.readable())
print(f.writable())
True
True
# a+t a+
with open(r'text.txt','a+',encoding='utf-8') as f:
print(f.readable())
print(f.writable())
True
True
二、文件内光标移动
假设我们需要在文件内容中间的某一行增加内容,如果使用基础的rwa模式实现是非常困难的,因此我们需要对文件内的指针进行移动。
硬盘上从来没有修改一说,硬盘上只有覆盖,即新内容覆盖老内容。
在rt模式下,read内的数字,表示的是字符的个数,除此之外,数字表示的都是字节
with open(r'text.txt','r',encoding='utf-8') as f:
print(f.read(5)) # 读取了5个字节
今天是一个
在rb模式下,read内的数字,表示的的是字节的个数。
with open(r'text.txt','rb') as f:
res = f.read(12)
print(res) # 读取的是12个字节 3个字节表示一个中文字符
print(res.decode('utf-8')) # 将二进制数据解码成utf-8二进制
b'xe4xbbx8axe5xa4xa9xe6x98xafxe4xb8x80'
今天是一
1.f.seek(offset,whence) 光标移动
- offset:相对偏移量 光标移动的位数
- whence:
- 0:参照文件的开头,t和b都可以使用
- 1:参照光标所在的当前位置,只能b使用
- 2:参照文件的末尾,只能在b模式中使用
# whence:0
with open(r'text.txt','rt',encoding='utf-8') as f:
print(f.read(1)) # 今
f.seek(6,0) # 从将光标从文件开头移动6bytes
print(f.read(1)) # 是 读取一个字符
# f.seek(4,0) # 将光标从开头移动了4个字节,由于汉字是由3个字节表示一个字符,所以会报错
f.seek(0,0) # 光标从开头移动0个字节,还在开头,
print(f.read(1)) # 读取一个字符
f.seek(6,0) #
print(f.read())
# whence:1
with open(r'text.txt','rb') as f:
print(f.read(3).decode('utf-8')) # 读取3个字节并用utf-8解码,(今)
f.seek(3,1) # 将指针从当前位置移动3个字节,
print(f.read(1)) # 读取一个字节
f.seek(6,0) # 将指针从文件开头移动6个字节,即2个字符
print(f.read(3)) # 读取3个字节
f.seek(4,0) # 将指针从文件开头移动4个字节,
print(f.read(2)) # 读取2个字节
# whence:3
with open(r'text.txt','rb') as f:
print(f.read()) # 读取文件内所有的字节
f.seek(-9,2) # 指针从末尾向前移动9个字节
print(f.read().decode('utf-8')) # 读取字节并解码成utf-8二进制
with open(r'text.txt','r+',encoding='utf-8') as f:
f.seek(3,0)
f.write('时') # 在第一个字符后面,写入一个字符,会将原来的字符覆盖掉
今时是一个好日子
今天是一个好日子
今天是一个好日子
今天是一个好日子
今天是一个好日子
今天是一个好日子
今天是一个好日子
今天是一个好日子
2.f.tell(int):查看光标移动了多少位
with open(r'text.txt','r+',encoding='utf-8') as f:
f.seek(18,0)
print(f.tell())
18
3.f.truncate(int):截断文件
接收字节的长度(保留0~6字节数,后面的全部删除)
truncate(n)是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate()要在r+或a或a+等模式下测试效果。它的参照物永远是文件头。并且teuncate()不加参数,相当于清空文件。
with open(r'text.txt','a',encoding='utf-8') as f:
f.truncate(12) # (12)接收的字节长度
# 保留0-12字节数,后面的全部删除(截断)
三、写日志、检测文件内容
# 写日志.py
import time
res = time.strftime('%Y-%m-%d %X')
with open(r'text.txt','a',encoding='utf-8') as f:
f.write(f'{res} egon给jason发了一亿的工资
')
# 检测文件内容
with open(r'text.txt','rb') as f:
f.seek(0,2) # 将光标移动到末尾
while True:
res = f.readline() # 每次读取光标后面的一行
# print(f.tell()) # 光标移动的字节数
if res: # 存在(即检测到新添加的内容)
print(f'新增的内容:{res.decode("utf-8")}') # 打印
# else:
# print('暂无其他人操作该文件')
四、修改内容
由于硬盘上从来没有修改一说,硬盘上只有覆盖,即新内容覆盖老内容。那我们如何修改文件呢?
方法一:
- 现将数据由硬盘读到内存(读取文件)
- 在内存中完成修改(字符串的替换)
- 再覆盖原来的内容(写文件)
with open(r'text.txt','r',encoding='utf-8') as fr:
data = fr.read()
print(data)
# print(type(data))
with open(r'text.txt','w',encoding='utf-8') as fw:
res = data.replace('egon','nick')
fw.write(res)
- 优点:任意时间硬盘上只有一个文件,不会占用过多硬盘空间
- 缺点:当文件过大的情况下,可能会造成内存溢出。
方法二:
- 创建一个新文件
- 循环读取老文件内容到内存进行修改,将修改好的内容写到新文件中
- 将老文件删除,将新文件的名字改为老文件。
import os
with open(r'text.txt','r',encoding='utf-8') as fr,
open(r'text.swap','a',encoding='utf-8') as fw:
for line in fr: # 将文件内容一行行读取
new_line = line.replace('nick','egon') # 对文件的每一行替换
fw.write(new_line) # 写入新文件
os.remove('text.txt') # 移除文件
os.rename('text.swap','text.txt') # 重命名文件