python 15 文件操作
一、计算机存储
- 默认情况下程序中的数据是保存在运行内存中的,当程序运行结束,在运行内存中保存的数据会自动销毁。
- 如果希望在这次运行程序的时候,可以使用上一次程序产生的数据,就必须把数据保存在硬盘(磁盘)中。
- 硬盘保存数据的最小单位是文件。
二、数据持久化
- 怎么将程序中的数据保存到文件中?
- 怎么在程序中获取文件中的内容?
答案:文件操作
三、文件操作
基本流程:打开文件—>文件读写操作—>关闭文件
1. 打开文件
语法:open(file,mode=‘r’,*,encoding=None)--------以指定的方式打开指定文件,返回一个文件的对象
1)参数1 --------- file :需要打开的文件路径(文件路径可以写绝对路径,也可以写相对路径)
-
绝对路径:文件在计算机中的全路径(windows从盘开始写的路径)
-
相对路径:在写文件路径的时候可以用 ‘.’ 和 ‘…’ ,‘.‘开头代表当前打开的文档所在文件,’…’ 开头代表当前打开的文档(文件)所在的文件夹的上级目录。(当前目录指的是当前代码文件所在的文件夹)
-
注意:如果使用相对路径,被打开的文件必须放在工程中;
如路径是以 ‘. / ’ 开头的,’ . / ’ 可以省略 -
案例:
open('./file/abc.txt') open('./test.txt')
2)参数2-------mode :文件的打开方式,用来决定打开文件之后能做什么(能读还是能写)、操作文件的时候,数据对应的类型(是字符串还是二进制)
-
给mode赋值的时候需要两组值:
-
第一组:决定打开后能做什么对应的值
- r : 只读-------打开不存在的文件,会报错。
- w : 只写-------打开的时候,会先清空文件里面的内容,打开不存在的文件不会报错,并且会自动创建文件。
- a : 只写--------打开的时候,不会清空原文件内容,打开不存在的文件不会报错,并且会自动创建文件。
-
第二组: 决定操作的文件的时候,数据的类型二选一,如果不选,就会默认选择 t 。
- t : 字符串
- b : 二进制(bytes)(图片数据音频是下载成二进制的)
-
赋值的时候,上面的两组值都必须选择一个(如果第二组值不选,就相当于选的是t )
- rt (tr) 、rb (br)、r、wt、wb、w、ab、at、a
-
案例说明
- 说明r只是读操作
f=open('./files/abc','r',encoding='utf-8') #拿到文件后,是一个对象,用一个变量名来命名。 f.read() #可以读 f.write('本地词语') #报错io.UnsupportedOperation: not writable,不支持写
-
说明w只是写,会清空原文件
f=open('./files/abc','w') f.write('sdfgh') #清空了原文件的内容,然后加上了’sdfgh‘ f.read() #报错,只能清空写不能读 io.UnsupportedOperation: not readable
-
说明a只是写,不会清空原文件
f=open('./files/abc','a') #k可以运行,不会报错,打开的文件里面的内容也在,没有清空 f.write('++++====cidbciyvc') #正常运行,加上了添加的内容sdfghcidbciyvc++++====cidbciyvc f.read() # 报错,不可读,只能写io.UnsupportedOperation: not readable
-
说明 t 对应的类型是字符串
f=open('./files/abc','r') #拿到文件 result=f.read() #把读到的结果记为result print(type(result)) ## <class 'str'> 输出的读到的数据的类型是字符串类型 f=open('./files/abc','rt') #拿到文件 result=f.read() #把读到的结果记为result print(type(result)) # <class 'str'> 输出的读到的数据的类型是字符串类型 f=open('./files/abc','rb') #拿到文件 result=f.read() #把读到的结果记为result print(type(result)) #<class 'bytes'> 输出读到的数据的类型是二进制,pdf,图片、音频存储方式是二进制 f=open('./files/abc','wb') #拿到文件 result=f.write('01') #把读到的结果记为result print(type(result)) #TypeError: a bytes-like object is required, not 'str'
-
说明t对应的类型是二进制
f=open('./files/abc','at') # 拿到文件 result=f.write('00000001') # 把读到的结果记为result print(type(result)) print(result)
-
尝试打开不存在的文件
=open('./files/fc.py','w') f.read() #报错,文件不存在[Errno 2] No such file or directory: './practice.py/abc' f.write('gdigy') # 会创建一个fc.py文件,这个在新文件里保存 g=open('./files/wer.txt','a') g.write('gcdiudi') #会创建一个wer.txt文件,这个在新文件里保存
3) 参数3--------encoding : 文本文件编码方式(只有在以t方式打开文件的时候,才需要encoding)
-
一般赋值为’utf-8’ 、‘gbk’ 也是一种常见的文件编码方式。windows的一些文本保存的编码格式是 ’ gbk ’
-
utf-8 : 文本数据在存储的时候,ascii码表中的符号用1个字节来存储,一个中文用三个字符来存储,可以对任何符号编码。
-
gbk : 文本数据在存储的时候,ascii码表中的符号用一个字节来存储,一个中文用2个字节来存储,除了ascii码表和中文外,不能对其他符号进行编码。
-
注意:乱码并没有说明数据有误,而是打开方式不对。
-
使用编码值的原则:存储数据的时候,使用编码值要和获取数据的时候,对应的编码值不一致。如果不设置,会默认是计算机的编码方式。
-
案例说明
f=open('./files/abc','w',encoding='utf-8') f.write('sgc你好') f=open('./files/abc','r',encoding='gbk') result=f.read() print(result) #sgc浣犲ソ编码值错误 #改正 f=open('./files/abc','r',encoding='utf-8') result=f.read() print(result) #sgc你好
- 如果输入的内容是全是字母,这两个编码方式都是同一个字符,所有没有影响。
2. 文件读写
1)文件读操作
-
语法1:文件 . read( ) ------获取整个文件的内容。
- 从读写位置开始,读到文件结束,读写位置默认在文件开头,随着读操作的进行(不管是read还是Readline),读写位置不断在改变。
-
语法2:文件 . readline( ) ------获取一行内容(只能文本文件有效)。
-
从读写位置开始至一行结束。
-
语法3:文件 . readlines( ) ------获取整个文件内容,返回一个列表,列表中的每个元素是每一行内容(只能文本有效)
-
案例操作:
#=============文件读操作=============== f=open('files/student.txt',encoding='utf-8') result=f.read() print(result) ##结果显示 # 鹅鹅鹅 # 曲项向天歌 # 白毛浮绿水 # 红掌拨清波 #=============readline ----读一行操作============ f=open('files/student.txt',encoding='utf-8') result=f.readline() print(result) #鹅鹅鹅 print('----------------------------冷静的分割线-------------------------------') #再读一行内容 result=f.readline() print(result) print('----------------------------冷静的分割线-------------------------------') #再次使用read来读文件 result=f.read() #前两次读的时候,光标停留在第三行的开头,所以,read读的时候,会继续在前面光标结束的位置开始,读完所有内容。 print(result) #结果显示 #白毛浮绿水 #红掌拨清波
-
注意:如果不想接着前面读到的位置开始读,想要一次性读写完所有的文件内容。
-
方法1.就直接重新打开文件,然后一次性读完
-
方法2;设置读写位置,f . seek(0) ,这条语句将读写位置移动到文件开头。
-
案例演示
f=open('./files/student.txt','r',encoding='utf-8') result=f.readline() print(result) #鹅鹅鹅 #此时光标已经停在了第二行的开头,但是想从头开始读,就用seek(0) f.seek(0) #让读写位置移动到文件开头 result=f.readline() #这个时候,还是读读的是鹅鹅鹅 print(result) #鹅鹅鹅 print('----------------------------冷静的分割线-------------------------------') f.seek(0) result=f.read() print(result) #读取内容 读到整个文件 # 鹅鹅鹅 # 曲项向天歌 # 白毛浮绿水 # 红掌拨清波 #————————————————————readlines --读一行操作,列表返回操作—————————————————————— f.seek(0) #因为前面的程序已经打开过f,不需要重新在打开文件,就直接使用seek(0),让光标移到开始的位置 result=f.readlines() print(result) #['鹅鹅鹅\n', '曲项向天歌\n', '白毛浮绿水\n', '红掌拨清波'] #返回值是以列表的形式返回,\n是换行,不想要可以采用切片去掉 print('----------------------------冷静的分割线-------------------------------')
-
2)文件写操作
-
语法1: 文件对象.write(数据)
-
语法2:文件对象 . writeline (数据)
写的时候,是以列表的形式输入进去。
-
注意:写的时候,如果选择w只会在第一次清空,后面多次选择w, b。不会多次选择w 不会清空,会继续添加新的内容进去。
-
案例演示
#============写操作======================= ’a‘是在后面继续添加内容,’w‘是清空之后再添加内容,所有要考虑好哪一种 f=open('./files/student.txt','a',encoding='utf-8') # result=f.write('\n只识弯弓射大雕,看同学少年,风华正茂') #\n表示换行添加,不写的话就是再原来光标的位置继续添加内容 # print(result) ''' 结果显示 鹅鹅鹅 曲项向天歌 白毛浮绿水 红掌拨清波 只识弯弓射大雕,看同学少年,风华正茂 ''' f=open('./files/student.txt','w',encoding='utf-8') result=f.write('***鹅鹅鹅,\n曲项向天歌,\n白毛浮绿水,\n红掌拨清波') ###\n表示换行添加,不写的话就是再原来光标的位置继续添加内容 result2=f.write('一代天骄,\n成吉思汗,\n只识弯弓射大雕,\n北国风光,千里冰封,万里雪飘,\n望长城内外,惟余莽莽,\n大河上下,顿失滔滔,\n山舞银蛇,原驰蜡象,\n欲与天公试比高') ''' 结果显示 ***鹅鹅鹅, 曲项向天歌, 白毛浮绿水, 红掌拨清波一代天骄, 成吉思汗, 只识弯弓射大雕, 北国风光,千里冰封,万里雪飘, 望长城内外,惟余莽莽, 大河上下,顿失滔滔, 山舞银蛇,原驰蜡象, 欲与天公试比高 '''
-
3. 关闭文件
-
语法:文件对象. close ( )
-
注意:关闭文件后,就无法操作,想要继续操作,就必须再把程序打开;为了安全起见,及时关闭。第二个,减少运行内存的占用。
-
案例演示
f.close() f.write('nxxxxxx') #关闭之后,运行文件,就会报错,ValueError: I/O operation on closed file.
四、文件操作的应用
数据持久化步骤:
- 第一步:确定需要持久化的数据
- 第二步:创建需要持久化数据的文件
- 第三步:确定文件初始内容(就是需要持久化的数据初始值)
- 第四步:在程序中需要这个数据的时候从文件中获取这个数据。
- 第五步:程序中如果修改数据以后,必须将最新的数据写到文件中。
#案例:写程序打印程序运行次数
#确定需要持久化的数据 - 运行次数
f=open('./runcount','r',encoding='utf-8') #打开已经创建好的持久化的数据
count=int(f.read()) #读到runcount的文本内容,因为是文本,所有要数据转换成int,
f.close() #关闭文件
count += 1 #运行次数+1
print(count) #打印运行次数
f=open('./runcount','w',encoding='utf-8') # 再次打开持久化文件
f.write(str(count)) # 将新的运行次数保存在持久化数据中
f.close() #关闭文件
-
练习:
#练习:提示用户输入名字添加学生,添加完后打印已经添加过的所有的学生名字 #1)确定需要持久化的数据 - 已经添加过的所有学生的名字 name=input('请输入你的名字') f=open('./practice.txt','at',encoding='utf-8') #先添加名字 f.write(input('请输入姓名:')+' ') f.close() f=open('./practice.txt','r',encoding='utf-8') #再读 a=f.read() f.close() print(a) ##上述方法先写再读 ##下述方法要先读再写 name=input('请输入姓名:') f=open('./practice.txt','r',encoding='utf-8') #先读 added_name=f.read() + name print(added_name) f=open('./practice.txt','w',encoding='utf-8') #再写 f.write(added_name+' ') # 请输入姓名:小红 # 小明 小兰 小红 f=open('./practice.txt','at',encoding='utf-8') f.write(a) f.close()
今日练习
设置登录注册界面
def get_all_user_name():
"""获取账号文件内容,并且将文件内容转换成字典"""
f=open('./practice/user_name.txt','rt',encoding='utf-8')
all_user= {}
for x in f.readlines(): #对取出来的列表进行遍历,列表中的每个元素都是字符串(即是用户名:密码)
name,pwsd = x .strip().split(':') #对列表的每个元素进行切割,返回的是被切割出来的每一段字符串组成的列表
all_user[name]=pwsd
f.close()
return all_user
def register():
# 1. 输入账号和密码
print('--------正在注册---------')
name = input('请输入账号(不能包含分号):')
pswd = input('请输入账号密码(不能包含分号):')
if ';' in name or ';' in pswd:
print('注册失败,账号不合法')
return #函数返回
# 2. 判断登录是否成功
# # 1)账号是否已经注册
all_user=get_all_user_name()
if name in all_user:
print('账号已经注册')
return
f=open('./practice/user_name.txt','at',encoding='utf-8')
f.write(f'{name}:{pswd}\n')
print('注册成功')
def login():
print('--------正在登录----------')
user_name=input('请输入账号:')
pswd=input('请输入密码:')
# 2. 判断登录是否成功
# 1)账号是否已经注册
all_user=get_all_user_name()
if user_name not in all_user:
print('该账号不存在,登录失败')
return
#2)密码是否正确
if all_user[user_name] != pswd:
print('密码错误')
else:
print('登录成功')
def welcom():
print('*********欢迎来到快乐星球**********')
print(f' 1. 登录\n\n\n 2. 注册')
print('********************************')
value=input('输入选项')
if value == '1':
login()
elif value == '2':
register()
else:
print('输入有误')
if __name__=='__main__':
welcom()