文件光标移动与文件数据修改
文件读写模式
python文件读写模式
模式组合 | \ | b | + | b+ |
---|---|---|---|---|
r | r | rb | r+ | rb+ |
w | w | wb | w+ | wb+ |
a | a | ab | a+ | ab+ |
具体意义
模式 | 具体意义 |
---|---|
r | 只可以读取文件。文件的指针将会放在文件的开头。这是默认模式。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。文件不存在的时候也会报错。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。读取的是二进制的文件例如图片、视频等。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 文件打开只可以用于写入内容,不可以进行其他操作。文件存在的时候,原有的内容会被覆盖。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。文件存在的时候,原有的内容会被覆盖。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。文件存在的时候,原有的内容会被覆盖。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。文件存在的时候,原有的内容会被覆盖。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件光标将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件光标将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件光标将会放在文件的结尾。新增的内容出现在光标后面。如果该文件不存在,创建新文件进行写入。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件光标将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
各读写模式对比
模式 | 读 | 写 | 创建 | 覆盖 | 指针位置 |
---|---|---|---|---|---|
r | 可读 | 在开始 | |||
r+ | 可读 | 可写 | 在开始 | ||
w | 可写 | 可创建 | 可覆盖 | 在开始 | |
w+ | 可读 | 可写 | 可创建 | 可覆盖 | 在开始 |
a | 可写 | 可创建 | 在结尾 | ||
a+ | 可读 | 可写 | 可创建 | 在结尾 |
文件操作方法
1. 可以通过with里的变量名使用for循环处理一些大的数据,每次取出来后会被垃圾回收装置回收,不会浪费资源
2. .read(),一次性读完文件内容光标移到文件末尾,如果还需要读的话那就读不到内容了
3. .readline(),一次读取一行内容
4. .readlines(),一次全部读完,将读取到的内容整理成列表的形式
5. .write(),每次写入之前都会被清空内容
6. .writable(),可不可以写入
7. readable(),可不可以读取
8. writelines(),支持容器类型写入,例如列表、字典等
作业讲解
#利用文件充当数据库编写用户登录、注册功能
# 文件名称:userinfo.txt
# 基础要求:
# 用户注册功能>>>:文件内添加用户数据(用户名、密码等)
# 用户登录功能>>>:读取文件内用户数据做校验
# ps:上述功能只需要实现一次就算过关(单用户) 文件内始终就一个用户信息
# 拔高要求:
# 用户可以连续注册
# 用户可以多账号切换登录(多用户) 文件内有多个用户信息
# ps:思考多用户数据情况下如何组织文件内数据结构较为简单
# 提示:本质其实就是昨天作业的第二道题 只不过数据库由数据类型变成文件
while True:
print('''
1.用户注册功能
2.用户登录功能
''')
funct_choice = input('请输入要执行的操作:').strip()
if funct_choice == '1':
# 获取用户的输入
username = input('输入用户名: ').strip()
# 读取文件,判断用户是否存在
with open(r'userinfo.txt', 'r', encoding='utf8') as read_f:
for info in read_f:
# 循环切割索引找到名字
data_name = info.split('|')[0]
if username == data_name:
print('用户已经存在')
break
else:
password = input('输入密码:').strip()
# 将用户名与密码改为字符串格式
user_data = '%s|%s\n' % (username, password)
# 写入文件中
with open(r'userinfo.txt', 'a', encoding='utf8') as write_f:
write_f.write(user_data)
print(f'{username}注册成功')
elif funct_choice == '2':
login_name = input('请输入用户名:').strip()
login_pwd = input('请输入密码:').strip()
with open(r'userinfo.txt', 'r', encoding='utf8') as read_f:
for info in read_f:
# 对用户与密码进行切割
data_name, data_pwd = info.split('|')
# 判断输入是否正确
if login_name == data_name and login_pwd == data_pwd.rstrip('\n'):
print('登录成功')
break
else:
print('用户名或密码有误')
else:
print('输入有误')
今日内容
文件内光标的移动
1.文件内光标的移动是以bytes为单位移动的,t模式下的read()是以字符移动的
with open('aaa.txt', mode='rt', encoding='utf-8') as read_f:
data = read_f.read(3) # 读取3个字符
print(data)
![image-20220630155328960](https://s2.loli.net/2022/06/30/Smt6p4XMagolzCK.png)
with open('aaa.txt', mode='rb') as f:
data = f.read(3) # 读取3个Bytes
data1 = f.tell() # .tell()可以获取移动的字节数
print(data)
print(data1)
![image-20220630160250594](https://s2.loli.net/2022/06/30/mhzMWfxwHTQiEX2.png)
2.文件内指针的移动不一定都是有读写操作被动的出发,可以通过一定的方法对其进行指定的移动
.seek(offset(光标移动的字节数,whence(模式控制))
'''0 模式,基于文件开头移动多少个字节,可以在t或者b模式下使用'''
with open(r'aaa.txt', 'rb') as f:
data = f.read(7) # aaaa要
print(data.decode('utf8'))
'''
一个英文字母以一个字节起步
一个中文以三个中文起步
'''
![image-20220630162412437](https://s2.loli.net/2022/06/30/4oEbkJyHTj7pWuA.png)
'''1 模式,基于光标当前所在位置移动的多少字节,只能在二进制模式下使用'''
with open(r'aaa.txt', 'r', encoding='utf8') as f:
data = f.read() # aaaa要吃中午饭了
print(data)
f.seek(0, 0)
print(f.read()) # aaaa要吃中午饭了
'''2 模式,基于文件末尾移动多少字节使用,只能在二进制模式下使用'''
with open(r'aaa.txt', 'rb') as f:
data = f.read(4)
print(data.decode('utf8')) # aaaa
# 光标在当前位置进行移动
f.seek(-3, 1)
print(f.read().decode('utf8')) # aaa要吃中午饭
# 光标在文件末尾移动
f.seek(-3, 2)
print(f.read().decode('utf8')) # 了
文件内数据修改
1.机械硬盘存储数据原理(文件对应的是硬盘空间,硬盘不能直接进行修改文件,断电后文件还存在)
数据的修改---覆盖写,将原来的覆盖掉重新写入
数据的删除---占有态自由态,
2.代码修改文件的方式
方式一:覆盖写
先读取文件内容到内存,在内存中完成修改,之后w模式打开该文件写入
with open(r'demo.txt', 'r', encoding='utf8') as f:
data = f.read()
new_data = data.replace('美人', '西施')
with open(r'demo.txt', 'w', encoding='utf8') as f1:
f1.write(new_data)
方式二:重命名
先读取文件内容到内存,在内存中完成修改,之后保存到另外一个文件中
再将原文件删除,将新的文件重命名为原文件
优点:不会造成内存溢出
缺点:有一段时间可能需要占用硬盘两个地方的空间(可能) 也可能是在内存中创建没有刷到硬盘
with open('demo.txt', 'r', encoding='utf8') as read_f, \
open('.demo.txt.swap', 'w', encoding='utf8') as wrife_f:
for line in read_f:
wrife_f.write(line.replace('西施', '美人'))
os.remove('demo.txt') # 删除文件
os.rename('.demo.txt.swap', 'demo.txt') # 重命名文件
作业
def regisetr(username, password):
with open(r'userinfo.txt', 'r', encoding='utf8') as read_f:
for info in read_f:
# 循环切割索引找到名字
data_name = info.split('|')[0]
if username == data_name:
print('用户已经存在')
break
else:
# password = input('输入密码:').strip()
# 将用户名与密码改为字符串格式
user_data = '%s|%s\n' % (username, password)
# 写入文件中
with open(r'userinfo.txt', 'a', encoding='utf8') as write_f:
write_f.write(user_data)
print(f'{username}注册成功')
return True
def login(username, password):
with open(r'userinfo.txt', 'r', encoding='utf8') as read_f:
for info in read_f:
# 对用户与密码进行切割
data_name, data_pwd = info.split('|')
# 判断输入是否正确
if username == data_name and password == data_pwd.rstrip('\n'):
print('登录成功')
break
else:
print('用户名或密码有误')
while True:
print('''
1.用户注册功能
2.用户登录功能
3.退出
''')
funct_choice = input('请输入要执行的操作:').strip()
if funct_choice == '1':
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
regisetr(username, password)
elif funct_choice == '2':
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
login(username, password)
elif funct_choice == '3':
print('欢迎下次再来哦')
break
else:
print('输入有误')