2.1 文件
文章目录
文件是为了持久化存储数据,有很多种类型的文件。内存存储的数据在断电之后会丢失,所以必须要有文件来存储。
2.1.1 文件的打开和关闭
1.文件的操作流程
1.打开文件,或者建立文件
2.读写数据
3.关闭文件
2.打开文件
我们可以使用内置的open函数,打开或者创建一个文件。
文件变量 = open(文件名,访问模式)
f = open('xxx.txt', 'w',encoding = "UTF-8" )
2个简单的访问模式说明,后面还有更多模式。
访问模式 | 说明 |
---|---|
r | 只用于读取,默认模式。文件不存在的话会报错。 |
w | 只用于写入,文件存在则先清空文件内容,文件不存在则创建新文件。 |
encoding指的是文件编码,我们Windows下的python环境默认是GBK,可能会导致乱码,记得转成UTF-8
2.关闭文件
文件变量.close()
如果程序结束程序也会自动打开的文件,但是一般情况下不会自动结束程序。
只有关闭了文件,文件内容才能真正写进去。
3.自动关闭文件(记忆)
with open("xxx.txt", "w") as f:
pass
2.1.2 文件的读写操作
1.文件的写操作
f = open("xxx.txt", "w")
f.write('str')
f.write('str2')
f.close()
#如果不执行close的时候是不会保存的
2.文件的读操作
1.按字符量读取
内容变量 = 文件变量.read(n)
n为读取的字符数,不设置则为全部读取。每次读取会移动一次光标,一次读取操作后光标不会重置回前面去,再次执行读操作会从当前光标开始读取。
2.全行读取
内容变量 = 文件变量.readlines(n)
会把每行读取成一个字符串,作为一个元素,存放到列表里,且会读取到换行符。
3. 按行读取
内容变量 = 文件变量.readline()
一次读取一行,也包含换行符。
3.文件的访问模式详解
访问模式 | 说明 |
---|---|
r | 只用于读,默认模式,如文件不存在会报错。 |
w | 只用于写,文件存在则清空文件内容,文件不存在则创建新文件。 |
a | 只用与写,文件存在则追加内容,文件不存在则创建新文件。 |
r+ | 用于读写,读是从文件开头读取,写从文件尾开始写入,写光标会跟随读光标移动,如果移动到开头,会覆盖前面的内容。文件不存在会报错 |
w+ | 用于读写,文件存在则清空文件内容,文件不存在则创建新文件。写从文件尾开始写入,写光标会跟随读光标移动,如果移动到开头,会覆盖前面的内容。 |
a+ | 用于读写,文件存在则追写内容,文件不存在则创建新文件,写光标只会在最后。 |
rb | 二进制格式的只读操作。后续网络课程中具体讲解。 |
wb | 二进制格式的只写操作。后续网络课程中具体讲解。 |
ab | 二进制格式的追写操作。后续网络课程中具体讲解。 |
拓展知识f.seek()
用来移动光标,但是一般移动的话只能移动到开头,想移动到具体的必须用二进制的读写方式。
4.文件的路径
1.绝对路径:
指文件完整的路径,是在硬盘上的路径。
比如一个文件在
E:\Code\Pycode
但是我们写代码的时候,Windows下的路径必须改,\
换成成\\
,或者用引号括起来'E:/Code/Pycode'
但是正常情况下很少应用绝对路径,因为会导致转移到其他环境的时候无法运行,因为路径不一致。
2.相对路径:
指文件相对于自己的目标文件的位置,不是完整的。
比如当前文件夹下有一个1.txt
,我们访问的时候可以直接写1.txt或者 ./1.txt
如果是上一级文件夹里的,则是../1.txt
也就是2个点对应的是当前文件位置的上一级文件夹。
2.1.3 文件的备份操作
如果我们想备份一个大文件,是没法一次性读取所有内容的,会超出缓存,我们选择使用一个循环,一次读取一点同时写入一点,那么这样就可以备份所有的内容了。
def main():
f_src = open(old_filename, "br")
f_dst = open(new_filename, "bw")
while True:
ret = f_src.read(1024)
if len(ret) == 0:
''' 注意 因为要读取的是任意文件而不是文本文件,所以我们不能用普通的r和w,得用br和bw,同时因为二进制读取是不能用字符串的空来判断的,得改成b'',也就是二进制的空,或者我们得把判断换成长度是0,或者直接用if not ret: 没读到东西就为真,有就为假,最后的一种方法最为泛用'''
break
else:
f_dst.write(ret)
f_src.close()
f_dst.close()
def new_filename(name_x):
old_name = name_x
index_sp = old_name.rfind('.')
l_str = old_name[:index_sp]
r_str = old_name[index_sp:]
new_name = l_str + '(备份)' + r_str
return new_name
old_filename = input("请输入要备份的文本名:")
new_filename = new_filename(old_filename)
main()
2.1.4 文件的操作(了解)
如果我们想对已有的文件进行操作,比如复制,粘贴,重命名之类的,我们需要用python内置的os模块,才能对系统内的文件进行操作。
import os
os.方法名()
1.文件重命名
os.rename("想改的文件名", "想更改后的文件名")
2.删除文件
os.remove("想删除的文件名")
3.创建文件夹
os.mkdir("文件夹名")
4.删除文件夹名
os.rmdir("文件夹名")
5.获取当前工作的绝对路径
work_path = os.getcwd()
print(work_path)
6.改变默认工作目录
os.chdir("../) 切换到上一级路径
7.获取目录列表,获取当前目录或者指定目录的文件信息
temp_list = os.listdir() 不指定的话是默认当前目录
8.判断文件是否存在
ret = os.path.exists("1.txt")
print(ret)
2.1.5 批量修改文件名(应用)
import os
name_list = os.listdir('renameTest')
print(name_list)
# 生成renameTest文件夹里所有文件的名字列表
os.chdir('renameTest')
# 切换到renameTest文件夹
for name in name_list:
new_name = "[黑马程序]-"+ name
os.rename(name, new_name)
new_name_list = os.listdir()
print(new_name_list)
输出
['123.txt', 'Good 123.txt', 'rest.txt']
['[黑马程序]-123.txt', '[黑马程序]-Good 123.txt', '[黑马程序]-rest.txt']
2.1.5 字符串和容器类型相互转换
我们可以用str()
讲一个列表转换成字符串,如下
user_list = [{'name': 'tom', 'age': 19, 'height': 1.78}, {'name': 'jerry', 'age': 25, 'height': 1.56},
{'name': 'john', 'age': 17, 'height': 1.90}]
print(type(user_list))
str_list = str(user_list)
print(type(str_list), str_list)
<class 'list'>
<class 'str'> [{'name': 'tom', 'age': 19, 'height': 1.78}, {'name': 'jerry', 'age': 25, 'height': 1.56}, {'name': 'john', 'age': 17, 'height': 1.9}]
如果我们想将类似的字符串也给转回去。
new_list = eval(str_list)
print(type(new_list), new_list)
new_dict = new_list[0]
print(type(new_dict), new_dict)
输出
<class 'list'> [{'name': 'tom', 'age': 19, 'height': 1.78}, {'name': 'jerry', 'age': 25, 'height': 1.56}, {'name': 'john', 'age': 17, 'height': 1.9}]
<class 'dict'> {'name': 'tom', 'age': 19, 'height': 1.78}
2.1.6 应用 学生名片信息系统增添读取和保存文件的功能
import os
# 学生的列表应为全局变量,我们采用列表嵌套字典,用于保存用户信息
student_list = []
# 我们应该设置一个函数,在运行的时候默认加载一个配置文件。
def load_local():
if os.path.exists("stu_list.config"):
print("读取到默认文件")
with open("stu_list.config", "r")as f:
user_str_list = f.read()
old_student_list = eval(user_str_list)
print("档案已经读取")
return old_student_list
else:
print("没有该文件,请重新选择配置文件读取")
# 制作一个保存学生信息到文件的功能,如果传参的话可以选择具体文件名
def save_file(file_name):
if os.path.exists(file_name):
print("原文件已经存在,是否覆盖?", end="")
user_sw = input("(yes or no) ")
if user_sw == 'no':
return
else:
print("覆盖该文件")
with open(file_name, "w") as f:
user_str_list = str(student_list)
f.write(user_str_list)
print("学生信息已保存")
# 制作一个读取本地文件里学生信息的功能,如果传参的话可以选择具体文件名
def load_file(file_name):
if os.path.exists(file_name):
print("读取到该文件")
with open(file_name, "r")as f:
user_str_list = f.read()
old_student_list = eval(user_str_list)
print("档案已经读取")
return old_student_list
else:
print("没有该文件,请重新输入")
# 主界面应为一个死循环,因为必须一直停留在当前页面选择,以下为主界面逻辑
def main():
global student_list
student_list = load_local()
while True:
menu_print()
user_select = int(input("请输入需要选择的功能:"))
if user_select == 1:
print("添加学生信息")
add_student()
elif user_select == 2:
print("查询所有学生信息")
check_all_student()
elif user_select == 3:
print("查询指定学生信息")
check_student()
elif user_select == 4:
print("编辑指定学生信息")
edit_student()
elif user_select == 5:
print("删除指定学生信息")
delete_student()
elif user_select == 6:
save_name = input("请输入要保存的文件名:")
save_file(save_name)
elif user_select == 7:
load_name = input("请输入要读取的文件名:")
student_list = load_file(load_name)
elif user_select == 8:
print("退出学生名片管理系统")
break
else:
print("输入错误,请重新输入")
# 显示主界面菜单,菜单是每次选择选项并且完全选项内容后会重复出现的东西,那么我们可以给写成函数来重复调用
def menu_print():
print("=" * 10, "学生名片管理系统", "=" * 10)
print("1.添加学生信息")
print("2.查询所有学生信息")
print("3.查询指定学生信息")
print("4.修改指定学生信息")
print("5.删除指定学生信息")
print("6.保存档案")
print("7.读取档案")
print("8.退出系统")
print("=" * 40)
'''
开始做第一个选项的函数,先分清逻辑顺序
首先我们要输入3个内容,名字,年龄,电话
然后用for循环遍历查看里面有没有名字冲突的,如果有则添加失败并且提醒,用break跳出循环
如果没有则进入else添加用户字典到列表里
'''
def add_student():
new_name = input("请输入学生的名称:")
new_age = int(input("请输入学生的年龄:"))
new_phone = input("请输入学生的电话号码:")
for a, student_dict in enumerate(student_list):
if student_dict['name'] == new_name:
print("该学生已经存在系统,无需再次添加")
break
else:
new_student = {'name': new_name, 'age': new_age, 'phone': new_phone}
student_list.append(new_student)
print("添加学生信息成功")
'''
实现查询所有学生信息的功能
我们直接用之前学的enumerate直接遍历所有即可,如果为空则跳出循环
提示系统目前没有任何学生信息
'''
def check_all_student():
if not student_list:
print("系统目前没有任何学生信息,请先添加学生信息")
else:
print("序号\t\t姓名\t\t年龄\t\t电话")
for n, student_dict in enumerate(student_list):
print('%d\t\t%s\t\t%d\t\t%s' % (n + 1, student_dict['name'], student_dict['age'], student_dict['phone']))
'''
实现查询指定学生的信息,
首先需要input来获取要查询学生的名字
然后遍历列表里的名字,如果没有则提示,有则显示内容
'''
def check_student():
check_name = input("请输入要查询的学生名字:")
for c, student_dict in enumerate(student_list):
if student_dict['name'] == check_name:
print("查到此学生")
print("学生信息如下\n")
print("序号\t\t姓名\t\t年龄\t\t电话")
print('%d\t\t%s\t\t%d\t\t%s' % (c + 1, student_dict['name'], student_dict['age'], student_dict['phone']))
break
else:
print("学生档案里无此学生的相关信息,请重新确认")
'''
同样的,我们要实现修改指定学生的档案,也是要经过一次筛选,但是不用Break跳过循环,
而是重新输入数据进行更改
'''
def edit_student():
check_name = input("请输入要修改的学生名字:")
for e, student_dict in enumerate(student_list):
if student_dict['name'] == check_name:
print("查到此学生")
print("学生信息如下\n")
print("序号\t\t姓名\t\t年龄\t\t电话")
print('%d\t\t%s\t\t%d\t\t%s' % (e + 1, student_dict['name'], student_dict['age'], student_dict['phone']))
edit_name = input("请输入要更改的学生名字:")
edit_age = int(input("请输入要更改的学生年龄:"))
edit_phone = input("请输入要更改的学生电话号码:")
student_list[e] = {'name': edit_name, 'age': edit_age, 'phone': edit_phone}
print("修改完成")
break
else:
print("学生档案里无此学生的相关信息,请重新确认")
'''
删除指定的学生档案同理
'''
def delete_student():
check_name = input("请输入要查询的学生名字:")
for d, student_dict in enumerate(student_list):
if student_dict['name'] == check_name:
print("查到此学生")
print("学生信息如下\n")
print("序号\t\t姓名\t\t年龄\t\t电话")
print('%d\t\t%s\t\t%d\t\t%s' % (d + 1, student_dict['name'], student_dict['age'], student_dict['phone']))
del student_list[d]
print("已删除该学生的信息")
break
else:
print("学生档案里无此学生的相关信息,请重新确认")
main()
# 字典输出问题,无法对齐提前打印的东西,格式化输出也不行,感觉需要一个表格才能限制,如果制表需要导入制表模块