文件处理
一 文件操作简介
应用程序在运行过程中产生的数据都是先存放在内存中,如果想要永久保存数据,就必须存到硬盘里,应用程序想要操作硬件,就必须通过操作系统,文件就是操作系统提供给用户操作硬盘的快捷方式之一。
二 文件操作流程
2.1 open() as f:
# 创建一个文件a.txt
# 关键字open
# 参数(file, mode='r', buffering=None, encoding=None,
# errors=None, newline=None, closefd=True)
f = open(r'a.txt', mode='r', encoding='utf8')
# 第一个参数文件路径,第二个参数模式,第三个参数编码格式
print(f.read()) # 今天学习的内容是文件的基本操作
f.close() # 回收系统资源
这种方式在操作完文件后需要添加f.colse()方法回收资源,我们可能会忘记,所以python提供了第二种写法。
2.2 with open() as f:
# 关键字with open() af 变量名:
with open(r'a.txt', mode='r', encoding='utf8') as f:
res = f.read()
print(res) # 今天学习的内容是文件的基本操作
# 这种方法在执行完with子代码后会自动执行close方法
# with语法补充
# 打开多个文件 中间用空格隔开
with open(r'userinfo.txt', mode='r', encoding='utf8') as f, open(r'xxx.txt', mode='r', encoding='utf8') as f1:
2.3 文件路径格式
在文件路径下面加r是为了统一格式
with open('D:\python\n\r', mode='r', encoding='utf8') as f:
# 如果不加r,python解释器会将\n\r识别成换行而不是一个路径
三 文件读写模式
3.1 r模式
只读模式,如果不写mode参数,默认为只读模式,以该模式打开文件,只能查看内容,不能进行其他操作。
# r模式
# 如果文件地址不正确则报错
# FileNotFoundError: [Errno 2] No such file or directory: 'test'
# 文件未找到:没有这样的文件或目录
with open(r'test', mode='r', encoding='utf8') as f:
res = f.read()
print(res)
# 文件路径存在 r模式会打开文件等待读取指令
with open(r'userinfo.txt', mode='r', encoding='utf8') as f:
res = f.read()
print(res) # jasper:123
f.write('jack:123') # 报错 io.UnsupportedOperation: not writable
# 不具备写的功能
3.2 w模式
只写模式,再能写内容不能进行其他操作,文件不存在时会创建新文档,文件存在时会清空文档,指针移到开头位置。
# w模式
with open(r'userinfo.txt', mode='w', encoding='utf8') as f:
# res = f.read()
# print(res) # 报错 io.UnsupportedOperation: not readable
# # 不具备读的能力
f.write('jack:123|')
f.write('jasper:123|')
f.write('lili:123|') # jack:123|jasper:123|lili:123|
# 文件在w模式下 连续的写入 后面的一定跟在前面的
# 重新以w模式打开文件 文件会被清空
3.3 a模式
只追加模式,只能追加内容不能进行其他操作,打开文件名不存在就新建一个文件,打开文件名存在,不会清空文件内容,并在文件末尾位置添加新内容。
# a模式
with open(r'userinfo.txt', mode='a', encoding='utf8') as f:
# res = f.read()
# print(res) # 报错 not readable
f.write('jack:123|') # 文件内:jack:123|jasper:123|lili:123|jack:123|
# a模式不会清空文件原本内容 并在文件尾部进行追加
3.4 x模式
创建一个新文件可写
# x模式
# 创建一个新的文件并打开写
with open(r'userinfo.txt', mode='x', encoding='utf8') as f:
pass
# 文件名存在则报错 [Errno 17] File exists: 'userinfo.txt'
# 文件名不存在则创建一个新的文件
with open(r'c.txt', mode='x', encoding='utf8') as f1:
print(f1.read()) # 不能读 报错 not readable
with open(r'd.txt', mode='x', encoding='utf8') as f2:
f2.writelines(['sss', 'eeee']) # 可以写
with open(r'e.txt', mode='xb') as f2:
f2.writelines(['sss'.encode('utf8'), 'eeee'.encode('utf8')]) # 支持二进制模式
3.5 +模式
打开一个磁盘文件,可读可写(r+ w+ a+)
# +模式
# 打开一个磁盘文件更新 可以读也可以写
with open(r'xxx.txt', mode='r+', encoding='utf8') as f:
pass # 文件名不存在报错 No such file or directory: 'xxx.txt' 没有这样的文件
with open(r'e.txt', mode='r+', encoding='utf8') as f1:
print(f1.read()) # ssseeee 可读
f1.write('xxx')
print(f1.read()) # ssseeeexxx 可写
with open(r'e.txt', mode='rb+') as f2:
print(f2.read()) # b'ssseeeexxxxxxxxxxxx'
f2.write('xixi'.encode('utf7')) # 支持二进制模式
四 文件操作模式
4.1 t模式
文本模式,文件操作默认模式,只能操作文本文件,必须给encoding传参,读写都是以字符串为单位。
4.2 b模式
二进制模式,可以操作任意类型文件,读写都是以bytes为单位,必须指定mode参数(rb/wb/ab),encoding参数为空或者不写。
# b
with open(r'userinfo.txt', mode='rb', encoding=None) as f:
res = f.read()
print(res) # b'\xe6\x96\x87\xe4\xbb\xb6'
五 文件操作方法
with open('userinfo.txt', mode='r', encoding='utf8') as f:
res1 = f.read() # 读取文件全部内容 继续读则为空
for line in f:
print(line) # 支持for循环 一次读一行
print(res1)
res2 = f.readline() # 读一行
print(res2)
res3 = f.readlines() # 读所有 返回列表里面是字符串
print(res3, type(res3))
res4 = f.readable() # 判断文件是否可读 返回布尔值
print(res4)
res5 = f.write('111') # 报错 不具备写的能力
print(res5)
res6 = f.flush() # 刷新
print(res6)
with open('userinfo.txt', mode='a', encoding='utf8') as f:
f.write() # 写单行
f.writelines(['666', 'aaa']) # 写多行 参数是列表里是字符串
f.writable()
作业
1.编写简易版本的拷贝工具
自己输入想要拷贝的数据路径 自己输入拷贝到哪个地方的目标路径任何类型数据皆可拷贝
ps:个别电脑C盘文件由于权限问题可能无法拷贝 换其他盘尝试即可
path = input('input copy path>>>:')
new_path = input('input copy to path>>>:')
with open(path, mode='rb') as read, open(new_path, mode='ab') as write:
write.write(read.read())
2.利用文件充当数据库编写用户登录、注册功能
文件名称:userinfo.txt
基础要求:
用户注册功能>>>:文件内添加用户数据(用户名、密码等)
用户登录功能>>>:读取文件内用户数据做校验
ps:上述功能只需要实现一次就算过关(单用户) 文件内始终就一个用户信息
拔高要求:
用户可以连续注册
用户可以多账号切换登录(多用户) 文件内有多个用户信息
ps:思考多用户数据情况下如何组织文件内数据结构较为简单
提示:本质其实就是昨天作业的第二道题 只不过数据库由数据类型变成文件
while True:
print("""
1.register function
2.loging function
""")
func = input('Enter function number as>>>:').strip(' ')
if func == '1':
# 获取用户注册用户名
usn = input('Enter username>>>:').strip(' ')
if usn == '': # 判断用户是否输入空
print('No input none')
continue
# 判断用户是否存在
with open(r'userinfo.txt', mode='r', encoding='utf8') as read:
for i in read:
# 先写存数据的格式 在完再写校验功能
# for循环拿到的是一个(usn:pwd换行符)的字符串
# 先去除字符串的换行符 在以冒号切片 得到用户名和密码列表
name, password = i.strip('\n').split(':') # ['jasper', '123']
if usn == name:
print('username already exists')
break
else:
# 获取用户密码
pwd = input('Enter password>>>:')
# 保存用户信息到文本文件
with open(r'userinfo.txt', mode='a', encoding='utf8') as write:
write.write(f'{usn}:{pwd}\n') # 存储格式为 usn:pwd换行
print('register successful')
elif func == '2':
# 获取用户账号和密码
usn = input('Enter username>>>:')
pwd = input('Enter password>>>:')
# 校验用户名和密码
with open(r'userinfo.txt', mode='r', encoding='utf8') as read:
for i in read:
# 根据存储数据的格式对数据处理 先去除字符串后的换行符 对列表进行解压赋值
username, password = i.strip('\n').split(':') # ['jasper', '123']
if usn == username and pwd == password:
print('loging successful')
break
else:
print('username or password error')
else:
print('Please enter correct function number as')
六 文件内光标移动
6.1 read()参数
# 光标移动
with open(r'userinfo.txt', 'r', encoding='utf8') as f:
res = f.read(3) # 在文本模式中 read内参数表示读取字符数
print(res)
with open(r'userinfo.txt', 'rb') as f1:
res = f1.read(3)
print(res) # b'jas' 在二进制模式下 read内参数指的是读取的bytes数
print(f1.tell()) # 3 获取文件内光标的位置
6.2 seek()参数
seek方法的offset参数为光标位移量(移动量为字节单位),wence参数是模式,wence有三种模式(0,1,2)
- 0
基于文件开头位置进行位移 - 1
基于文件光标当前位置进行位移 - 2
基于文件末尾位置进行位移
ps:1和2模式只能在二进制模式打开的文件下使用
# seek()
# 参数:offset:控制光标移动的位移量, whence:模式
with open(r'userinfo.txt', 'r', encoding='utf8') as f:
print(f.tell()) # 0
f.seek(10, 0)
print(f.tell()) # 10
with open(r'userinfo.txt', 'rb') as f1:
print(f1.tell()) # 0
f1.seek(10, 0)
print(f1.tell()) # 10
f1.seek(-1, 1)
print(f1.tell()) # 9
f1.seek(-1, 2)
print(f1.tell()) # 31
小练习
动态查询输入内容
# 动态查询日志
import time
with open(r'userinfo.txt', 'rb') as f:
f.seek(0, 2)
while True:
line = f.readline()
if len(line) == 0:
time.sleep(0.5)
else:
print(line.decode('utf8'))
# 文件写入内容
while True:
with open(r'userinfo.txt', 'ab') as f1:
f = input('>>>:')
new = f.encode('utf8')
f1.write(new)
七 文件数据修改
7.1 机械硬盘存储数据的原理
修改数据:数据覆盖
保存数据:占有态和自由态
7.2 代码修改文件
方式一:覆盖写,将文件先读到内存,在内存内完成修改,在以w模式打开该文件并写入。
with open(r'userinfo.txt', 'rb') as f:
old = f.read().decode('utf8').replace('s', 'b')
with open(r'userinfo.txt', 'wb') as f:
new = old.encode('utf8')
f.write(new)
# 优点:硬盘只占用一块空间
# 缺点:数据内容太大会造成内存溢出
方式二:重命名,将文件读到内存,在内存中完成修改,之后保存到另一个文件夹中,再将原文件删除,再将修改后的文件重命名。
# 重命名
with open(r'userinfo.txt', 'rb') as f, open(r'a.txt', 'ab') as f1:
for line in f:
f1.write(line.decode('utf8').replace('b', 's').encode('utf8'))
import os
os.remove('userinfo.txt')
os.rename('a.txt', 'userinfo.txt')
# 优点:不会有内存溢出的问题
# 缺点:额外申请了空间