文件与文件路径的操作
程序员在运行程序的过程中往往会产生一些零时数据,但程序结束后,这些零时数据也会随之消失。那么有没有办法将这些数据持久化到磁盘中呢?当然是可以的,计算机文件会永久保存运行时产生的数据。
1.文件的打开和关闭
想要将数据写入到文件中,需要先打开文件,数据写完之后,需要将文件关闭以释放内存。
1.1.文件的打开
Python提供函数open()打开文件,该函数调用成功会返回一个文件对象,语法格式如下:
open(file,mode='r',encoding=None)
# 参数file表示要打开的文件名
# 参数encoding表示打开文件的编码格式
# 参数mode设置文件的打开模式,其常用的模式如下:
r:以只读的方式打开文件,默认值
w:以只写的方式打开文件;
a:以追加的方式打开文件。
在实际的开发过程中,文件的打开模式可以搭配b、+使用,具体搭配如下表:
打开模式 | 名称 | 描述 |
---|---|---|
r/rb | 只读模式 | 以只读的形式打开文件/二进制文件,若文件不存在或无法找到,open()函数将调用失败 |
w/wb | 只写模式 | 以只写的形式打开文件/二进制文件,若文件已存在,则重写文件,否则创建文件 |
a/ab | 追加模式 | 以只写的形式打开文件/二进制文件,只允许在文件末尾追加数据,若文件不存在,则创建新文件 |
r+/rb+ | 读取(更新)模式 | 以读写的形式打开文件/二进制文件,如果文件不存在,open()函数调用失败 |
w/wb+ | 写入(更新)模式 | 以读写的形式创建文件/二进制文件,若文件已存在,则重写文件 |
a+/ab+ | 追加(更新)模式 | 以读写的形式打开文件/二进制文件,但只允许在文件末尾添加数据,若文件不存在,则创建新文件 |
1.2.文件的读取
文件的读取有3种方式,read(),readline(),readlines():
- read():从指定文件中读取指定数据;
文件对象.read([size])
# 参数size用于设置读取数据的字节数,若没有则一次读取文件的所有数据
- readline():从指定文件读取一行数据;
文件对象.readline()
- readlines():一次读取文件的所有数据。
文件对象.readlines()
# 使用readlines()方法读取数据后回返回一个列表,文件的每一行对应列表中的一个元素
1.3.文件的关闭
Python内置函数close()用于关闭文件,该方法不需要参数,直接调用。计算机的内存打开文件的数量是有限的,打开的文件占用系统的资源,降低系统的性能。因此需要用close()方法主动关闭不再使用的文件。
文件对象.close()
# 文件的打开
"""
file:文件名
mode:文件打开的方式,r-只读打开,w-只写打开,a-追加打开
encoding:字文件的编码格式,常见gbk和utf-8
返回值是一个文件对象
"""
txt = open("test.txt", mode='r', encoding="utf-8")
print(txt)
# 文件的读取
print("read():")
buff01 = txt.read()
print(buff01)
print("读取文件n个字节数:")
txt = open("test.txt", mode='r', encoding="utf-8")
print(txt.read(2))
# 读取文件一行数据
txt = open("test.txt", mode='r', encoding="utf-8")
print("readline():")
buff02 = txt.readline()
print(buff02)
# 读取文件所有数据
txt = open("test.txt", mode='r', encoding="utf-8")
print("readlines():")
buff03 = txt.readlines()
print(buff03)
# 文件的关闭
txt.close()
2.文件的读写操作
Python提供了write()方法和writlines()方法向文件写入数据:
- write()
文件对象.write(str)
# str表示要写入的字符串,若写入成功,则返回本次写入的文件长度
- writelines()
文件对象.write([str])
# 向文件写入字符串序列
# 文件的打开
file = open('a.txt', 'w', encoding='utf-8')
# 文件的写入,若文件不存在,会创建,若文件存在,不执行write()写入内容,会清空内容
# \n 表示换行,如果没有不会换行
print("write()...")
file.write("hello world\n")
file.write("人生苦短,快用Python")
# 文件的打开
file = open('a.txt', 'w', encoding='utf-8')
# writelines()向文件写入字符串序列
print("writelines()...")
str = ["\n" + "life is short,you need python",'\nPython好学']
file.writelines(str)
# 关闭
file.close()
3.文件定位读取
在系统中文件的一次打开和关闭之间的读写操作都是连续的。程序总在上次读写的位置进行读写操作,但有时候会指定到某一位置来进行读写操作,这个时候我们就要用到文件读写位置的属性来进行操作。
Python提供用于获取文件读写位置及修改文件读写位置的tee()和seek()方法。
3.1.tell()方法
tell()方法用于获取当前文件读写的位置,格式为:
text.tell()
# 文件的打开
file = open('a.txt', 'r', encoding='utf-8')
print(file.read(5)) # 读取5个字节
print(file.tell()) # 15 输入文件读取的位置(汉字为3个字节)
3.2.seek()方法
seek()方法用于设置当前文件读写的位置,格式为:
txt.seek(offset,from)
seek()方法的参数offsert表示偏移量, 即读写位置需要移动的字节数;参数from用于指定文件的读写位置,该参数的取值有以下三个:
-
0:表示在开始位置读写
-
1:表示在当前位置读写
-
2:表示在末尾位置读写
file = open(‘a.txt’, ‘w’, encoding=‘utf-8’)
file.seek(3,0)
print(file.write(“你好!!”))
file.close()
## 4.文件的复制和重命名
### 4.1.文件的复制
文件的复制即创建文件的副本,此项操作的本质仍是文件的打开、关闭和读写操作。复制文件的基本步骤如下:
1. 打开文件;
2. 读取文件内容;
3. 创建新的文件,将数据写入到文件中;
4. 关闭文件,保存数据。
具体实现如下:
```shell
# 文件的复制
file_name = "test.txt"
source_file = open(file_name,"r",encoding="utf-8")
all_data = source_file.read()
flag = file_name.split(".")
new_file = open(flag[0] + '备份' + ".txt",'w',encoding="utf-8")
new_file.write(all_data)
source_file.close()
new_file.close()
4.2.文件的重命名
Python提供了直接用于更改文件名的函数rename(),该函数的语法如下:
rename(源文件名,新文件名)
需要注意的是:这个函数存在于os模块中,需要导入os模块才能使用:
# 文件的复制
import os
os.rename("test.txt","test01.txt")
需要注意的是:需要重命名的文件必须存在,否则会报错。对于操作系统来说,文件和文件夹都是文件,所以该函数也对文件夹有效:
import os
# os.rename("test.txt","test01.txt")
os.rename("测试","重命名")
5.练习:通讯录
要求编写通讯录程序,接收用户输入的姓名、电话、qq号、邮箱等信息,将这些信息保存到"通讯录.txt"文件中,实现新建联系人功能;可根据用户输入的联系人姓名查找联系人,展示联系人的姓名、电话等信息,实现查询功能。
import sys
import json
class TelephoneBook:
def show_menu(self): # 用于界面展示
print("*" * 20)
print("欢迎使用[通讯录] V1.0")
print("1. 新建联系人")
print("2. 查询联系人")
print("0. 退出系统")
print("*" * 20)
def add_info(self):
name_str = input("请输入姓名:")
phone_num = input("请输入电话:")
qq_num = input("请输入QQ号码:")
mail_adr = input("请输入邮箱:")
# 将数据封装到字典中
card_dict = {"姓名": name_str, "手机号": phone_num,
"qq": qq_num, "mail": mail_adr}
f = open("通讯录.txt", mode='a+', encoding='utf-8')
# 将字典转换为str,然后再使用write()写入到通讯录的文本文件中
f.write(str(card_dict) + '\n')
f.close()
print(f"成功添加{name_str}为联系人")
# 显示联系人信息
def show_info(self):
file = open("通讯录.txt", mode='r', encoding='utf-8')
# 如果通讯录.txt文件不为空时,执行下面代码
if len(file.read()) != 0:
# 保证每次从开始位置读取
file.seek(0, 0)
# 读取通讯录.txt文件中的内容
file_data = file.read()
# 对字符串进行分隔
split_info = file_data.split('\n')
# 删除多余的字符串
split_info.remove(split_info[len(split_info) - 1])
name = input("请输入要查询的姓名:")
name_li = [] # 用于存储联系人姓名的列表
all_info_li = [] # 用于存储所有信息的列表
for i in split_info:
# 将单引号替换为双引号
dict_info = json.loads(i.replace("\'", '\"'))
all_info_li.append(dict_info)
# 获取所有联系人的姓名
name_li.append(dict_info['姓名'])
if name in name_li:
for person_info in all_info_li:
for title_key, name_value in person_info.items():
if name_value == name:
for title, info_value in person_info.items():
print(title + ":" + info_value)
else:
print('联系人不存在')
else:
print("通讯录为空")
def main(self):
while True:
self.show_menu()
action_str = input("请选择操作功能:") # 判断用户输入的功能指令
if action_str.isdigit() is True:
if int(action_str) == 1:
self.add_info()
elif int(action_str) == 2:
self.show_info()
elif int(action_str) == 0:
sys.exit()
else:
print('请输入正确的指令')
if __name__ == '__main__':
tb = TelephoneBook()
tb.main()
6.目录的操作
os模块定义了一些用于处理文件夹的操作函数,例如创建目录、获取文件列表等函数;除了os模块外,Python中的shutil模块也提供了文件夹的操作。
6.1.创建目录
os模块提供了mkdir()函数用于创建目录,语法格式为:
os.mkdir(path,mode)
- path:表示要创建的目录,参数mode表示目录的数字权限,该参数在Windows系统下可以忽略。
在创建目录的操作中需要判断目录是否存在,如果存在则提示用户,如果不存在则可以创建并可写入数据:
# 创建目录
import os
dir_path = input("请输入要创建目录:")
# 判断目录是否存在
y_or_n = os.path.exists(dir_path)
if y_or_n is False:
os.mkdir(dir_path)
new_file=open(os.getcwd()+"\\"+dir_path+"\\"+"dir_demo.txt","w",encoding="utf-8")
new_file.write("life is short, use Python.")
print("写入成功")
else:
print("该目录已经存在!")
6.2.删除目录
使用shutil模块的rmtree()函数可以实现删除目录,语法格式为:
rmtree(path)
path为要删除的目录
# 删除目录
import os
import shutil
# 判断目录是否存在
print(os.path.exists("重命名"))
shutil.rmtree("重命名")
# 确认目录是否删除
print(os.path.exists("重命名"))
6.3.获取目录的文件列表
os模块中的listdir()函数用户获取文件夹下文件或文件名的列表,该列表按字母顺序排序,语法格式为:
listdir(path)
# 获取文件夹列表
current_path = r"D:\Software"
print(os.listdir(current_path))
7.文件路径操作
7.1.相对路径路径和绝对路径
文件的相对路径指某文件(或目录)所在的路径与其他文件(或目录)的路径关系,绝对路径指从盘符开始到当前位置的路径。os模块提供了用于检测目标路径是否是绝对路径isabs()函数和将相对路径规范化为绝对路径的abspath()函数。
- isabs()函数
当目标路径为绝对路径时,isabs()函数会返回True,否则会返回False。
# 路径操作
import os
print(os.path.isabs("test01.txt"))
print(os.path.isabs("D:\Software"))
- abspath()函数
当目标文件为相对路径时,使用该函数可以将路径规范化为绝对路径:
print(os.path.abspath("test01.txt"))
7.2.获取当前路径
当前路径即文件、程序或目录当前所处的路径,os模块提供了getcwd()函数用于获取当前路径:
current_path = os.getcwd()
print(current_path)
7.3.检测路径的有效性
os模块中的exists()用于判断路径是否存在,如果当前路径存在,函数返回True,如果不存在则返回False。
# 判断路径是否存在
import os
current_path = "D:\Software"
current_path_file = "D:\Software\jdk-17.0.2"
print(os.path.exists(current_path)) # True
print(os.path.exists(current_path_file)) # True
7.4.路径的拼接
os模块中join()函数用于拼接,语法格式为:
os.path.join(path1,[path2,....])
import os
path01 = "D:\Software"
path02 = "jdk-17.0.2"
# windows下默认使用/分隔
sumpath = os.path.join(path01, path02)
print(sumpath)
# 如果后面路径为空,则用\来结尾
path03 = ""
sumpath02 = os.path.join(path01, path03)
print(sumpath02)
8.练习:实现用户登录
登录用户通常分为普通用户登录,管理员登录。在用户登录时,可以根据自身的权限进行选择登录。
要求:
- 实现普通用户和管理员的登录
- 管理员账号密码在程序中设置,普通用户账号与密码通过注册功能添加
- 创建文件u_root.txt,写入管理员:
{'rnum': 'root', 'rpwd': '123456'}
# author by Michealzou@126.com
# 2022/5/12 19:24
import os
# 判断是否首次使用系统
def is_first_start():
if os.path.exists('flag.txt') == False:
print('首次启动')
flag = open('flag.txt', 'w+')
flag.write('1')
flag.close() # 关闭文件
init() # 初始化资源
print_login_menu() # 打印登录菜单
user_select() # 选择用户
else:
flag = open('flag.txt', 'r')
word = flag.read()
if len(word) == 1:
init() # 初始化资源
print_login_menu() # 打印登录菜单
user_select() # 选择用户
# 初始化管理员
def init():
if os.path.exists('users') == False:
file = open('u_root.txt', 'w') # 创建并打开管理员账户文件
root = {'rnum': 'root', 'rpwd': "123456"}
file.write(str(root)) # 写入管理员信息
file.close() # 关闭管理员账户文件
os.mkdir('users') # 创建普通用户文件夹
# else:
# 打印登录菜单
def print_login_menu():
print('----用户登录----')
print('1-管理员登陆')
print('2-普通用户登陆')
print('--------------')
# 用户选择
def user_select():
while True:
user_type_select = input('请选择用户类型')
if user_type_select == '1': # 管理员登陆验证
root_login()
break
elif user_type_select == '2': # 普通用户
while True:
select = input('是否需要注册?(y/n):')
if select == 'y' or select == 'Y':
print('----用户注册----')
user_register() # 用户注册
break
elif select == 'n' or select == 'N':
print('----用户登录----')
break
else:
print('输入有误,请重新选择')
user_login() # 用户登录
break
else:
print('输入有误,请重新选择')
# 管理员登陆
def root_login():
while True:
print('****管理员登陆****')
root_number = input('请输入账户名:')
root_password = input('请输入密码:')
file_root = open('u_root.txt', 'r') # 只读打开文件
root = eval(file_root.read()) # 读取账户信息
# 信息匹配
if root_number == root['rnum'] and root_password == root['rpwd']:
print('登陆成功!')
break
else:
print('验证失败')
# 用户注册
def user_register():
user_id = input('请输入账户名:')
user_pwd = input('请输入密码:')
user_name = input('请输入昵称:')
user = {'u_id': user_id, 'u_pwd': user_pwd, 'u_name': user_name}
user_path = "./users/" + user_id
file_user = open(user_path, 'w') # 创建用户文件
file_user.write(str(user)) # 写入
file_user.close() # 保存关闭
# 普通用户登录
def user_login():
while True:
print('****普通用户登录****')
user_id = input('请输入账户名')
user_pwd = input('请输入密码:')
# 获取user目录中所有的文件名
user_list = os.listdir('./users') # 遍历元组,判断user_id是否在元组中
flag = 0
for user in user_list:
if user == user_id:
flag = 1
print('登录中····')
# 打开文件
file_name = './users/' + user_id
file_user = open(file_name)
# 获取文件内容
user_info = eval(file_user.read())
if user_pwd == user_info['u_pwd']:
print('登录成功!')
break
if flag == 1:
break
elif flag == 0:
print('查无此人!请先注册用户')
break
if __name__ == '__main__':
is_first_start()