day-09
1. 文件处理
-
什么是文件
操作系统提供的虚拟概念,存储信息(用二进制存储)
-
什么是文件处理
修改存储的信息
-
文件的绝对路径和相对路径
- 文件的路径:文件在硬盘的地址
- 绝对路径:从盘符开始的路径:
D:\Program Files\python\test.py
- 相对路径:执行文件(当前运行的文件)的文件夹下的文件名,执行文件和打开文件属于同一文件夹下:
test.py
项目中尽量用相对路径。
-
操作文件的流程
-
打开文件
- 找到文件所在的路径
- 选择打开的模式
- 指定字符编码
f = open('test.py','r',encoding='utf-8') # 以‘r’模式,‘utf-8’格式,打开当前文件夹下的‘test.py’
-
读取 或 修改文件
data = f.read() # 读取文件内的内容给到对象 data
-
保存文件
f.flush() # 快速保存,可以不使用
-
关闭文件
f.close() # 告诉操作系统关闭文件
-
2. 文件的三种打开模式和两种方式
- 文件的三种打开模式
-
读取:
rt
:读文本内容,只读f = open('test.py','r',encoding='utf-8') data = f.read() # 读取所有文本内容 print(f.readable()) # 判断是否可读 print(f.writable()) # 判断是否可写
运行结果:
True False Process finished with exit code 0
-
了解
print(f.readline()) # 一行一行读取 print(f.readlines()) # 读取所有行放入列表
-
循环读出文本内容
for i in f.read(): # 循环出一个个字符 print(i)
for i in f: # 循环出一行行的内容 --->这种方式更节省内存 print(i)
-
-
只写:
wt
:打开文件后先清空文本内容,再写入新的内容f = open('test.py','w',encoding='utf-8') print(f.readable()) # 判断是否可读 print(f.writable()) # 判断是否可写
运行结果:
False True Process finished with exit code 0
-
了解
f.writelines(['abc', 'def', 'ghi']) # 自动拼接列表元素,一行写入
文件内保存为:
abcdefghi
-
-
只写:
at
:只写,在文件原内容最后面写入新的内容f = open(r'D:\上海python12期视频\python12期视频\day 09\test.py', 'at', encoding='utf8') print(f.readable()) print(f.writable())
运行结果:
False True Process finished with exit code 0
使用
w
和a
模式可以自动创建一个新的文件,使用r
模式时,文件必须是已经存在的。
-
文件的两种打开方式
两种方式都不单独使用,一般与r/w/a联用
-
文本方式:
t
:打开文本,需要指定字符编码指定打开的文本文件的模式为
rt 或 wt 或 at
,一般可以省略 t 直接写作r 或 w 或 a
。 -
二进制方式:
b
:一般用于音频/视频/图片的保存指定打开的文本文件的模式为
rb 或 wb 或 ab
。
3. with 管理文件上下文
由于每次保存文件后,都需要手动将文件关闭掉,解除对操作系统的占用,比较麻烦,所以python中提供了一种可以自动关闭文件的方法。
-
语法:
with open('test.py', 'r', encoding='utf8') as f: # print(f.read()) # 在这个缩进下不会关闭文件,在这个缩进下对文件操作 data = f.read() # data放到python的内存中 print(data) # 关闭文件(操作系统),但没有关闭python内存中的文件 print(f.read()) # 由于不在缩进内,操作系统的文件已经关闭,报错
4. 文件的高级应用(了解)
1.三种新的文件打开模式(使文件即可读又可写),尽量不要使用。
当一个文件即可读又可写的时候,由于读取和写入的时间差,可能出现写入和读取的错误,无法正确的读取到或者写入我们想要的信息。
-
可写可读:
r+
with open('test.py', 'r+', encoding='utf8') as fr: print(fr.readable()) print(fr.writable()) fr.write('写入内容') # 光标在文件头部,会覆盖后面的字符
运行结果:
True True Process finished with exit code 0
-
可写可读:
w+
:w+
和w
没有任何区别with open('test.py', 'w+', encoding='utf8') as fw: print(fw.readable()) print(fw.writable())
运行结果:
True True Process finished with exit code 0
-
可写可读:
a+
:a模式默认光标在尾部with open('test.py','a+',encoding='utf8') as fa: print(fa.readable()) print(fa.writable()) fa.seek(0,0) # 由于 a 模式打开文件,默认光标在尾部,所以想要读取文件内容必须将光标移动到文件头 print(fa.read())
运行结果:
True True Process finished with exit code 0
综上,如果某些场景真的需要文件可读又可写,应该用两种不同的模式打开两次文件
2.光标的高级应用(移动文件内的光标)
-
字节:8个二进制位为一个字节(以下方法都是以字节为单位)
-
seek()
:移动光标with open('test.py', 'rb') as fr: fr.seek(3) # 打开文件后,将光标往后移动3个字节(一个中文),默认从开头开始读取 # 如果 seek 移动的字符不够 3 个字节,或刚好将汉字的三个字节切分,则会导致乱码 # whence 参数:规定只有0,1,2 三种模式 fr.seek(3, 0) # 0 表示从开头往后移动 3 个字符,默认为 0 ,可以不写 fr.seek(3, 1) # 1 表示从中间往后移动 3 个字符 fr.seek(3, 2) # 2 表示从开头往后移动 3 个字符 print(fr.read()) print(fr.read().decode('utf8'))
-
tell()
:告诉当前光标所在的位置with open('test.py', 'rb') as fr: fr.seek(3, 0) print(fr.tell()) # 从文件开头到当前指针所在位置
运行结果:
3 Process finished with exit code 0
-
truncate()
:截断with open('test.py', 'ab') as fa: fa.truncate(2) #截断2个字节后的所有字符,如果3个字节一个字符,只能截断2/3个字符,还会遗留1/3个字符,会造成乱码
-
-
字符:3个字节对应一个字符(中文)
-
read()
:以字符为单位,移动光标with open('test.py', 'r', encoding='utf8') as fr: print(fr.read(3)) # 3 表示 3 个字符,不加默认读取所有 # 中文和英文都属于一个字符
-
5. 文件的修改
文件没有修改的说法,只有覆盖。
缓存文件的原理:
import os
# 同时打开多个文件
with open('test.py', 'r', encoding='utf-8') as fr, \
open('test_swap.py', 'w', encoding='utf-8') as fw:
data = fr.read()
data = data.replace('原内容', '修改的内容') # 在新文件里用修改的内容替换掉原来的内容
fw.write(data)
os.remove('test.py') # 删除原文件
os.rename('test_swap.py', 'test.py') # 将新的文件重命名为旧文件
但是这样当文件很大的时候,影响效率,下面是改进:
import os
# 同时打开多个文件
with open('test.py', 'r', encoding='utf8') as fr, \
open('test_swap.py', 'w', encoding='utf8') as fw:
# 逐行修改保存,再大的文件都能修改
for i in fr:
s = '新的内容'
i = i.replace('原内容', s)
fw.write(i)
# fw.flush() # 先保存成功再继续运行
os.remove('test.py') # 删除原文件
os.rename('test_swap.py', 'test.py') # 将新的文件重命名为旧文件
6. 登录注册
-
注册功能:
-
实现代码:
# 注册 count = 0 while count < 3: username_inp = input('请输入你的用户名:') pwd_inp = input('请输入你的密码:') re_pwd_inp = input('请在此输入你的密码:') if not pwd_inp == re_pwd_inp: print('两次密码输入不一致') count += 1 continue with open('user_info.txt', 'a', encoding='utf8') as fa: fa.write(f'{username_inp}:{pwd_inp}\n') # :表示用户名和密码的分割;|用户和用户之间的分割 fa.flush() break
-
-
登录功能:
-
实现代码:
# 登录 username_inp = input('请输入你的用户名:') pwd_inp = input('请输入你的密码:') with open('user_info.txt', 'r', encoding='utf8') as fr: for user_info in fr: username, pwd = user_info.split(':') if username.strip() == username_inp and pwd.strip() == pwd_inp: # strip可以去掉两端的换行符 print('登录成功') break else: print('登录失败')
-