赞
踩
在前面的学习中,我们已经学习了input和print。这两个函数,在开发中我们一般称之为标准输入和输出。
input 接收用户在标准输入(默认的标准输入是键盘)下录入的字符串信息
print 把数据以字符串格式输出到标准输出中(默认的标准输出是终端)
但是,上面的读写操作并不能让我们把数据长期稳定保存下来,所以关闭了终端以后,数据就没有了。
因此,我们如果需要长期而稳定的保存数据下来,就需要把数据保存到文件中(一般这个操作,我们称之为持久化存储)。
文件操作对编程语言非常重要,如果数据不能持久化存储,信息技术也就失去了意义。
Python中用于文件目录操作的常用模块有默认文件操作、os(操作系统模块), shutil(shell工具),pathlib(目录操作),fileinput(批量文件操作)等。
Python内置了一个open()函数可以用于创建一个指定文件,如果文件已存在,则表示打开该文件。语法:
# 1. 默认只读模式打开文件,如果文件不存在,则报错 FileNotFoundError。
file: object = open(file_name: str)
# 2. 以指定访问模式打开文件
file: object = open(file_name: str, access_mode: str="r")
# 3. 以指定访问模式、指定编码格式打开文件
file: object = open(file_name: str, encoding: str=None)
参数选项说明:
file_name:文件的存储路径和文件名,如果路径与运行的python入口文件在同一个目录下,可以省略不写。
access_mode:打开文件的访问模式
encoding:编码类型,常用编码:utf-8, gbk
/ 在文件目录中,表示目录分隔符,用于表达文件和目录之间的包含关系的
. 在文件目录中,表示当前目录,是一种以当前文件的位置作为参考值,表达文件/目录所在位置的一种相对表达方式,例如生活中的,我的对面,我的隔壁,
.. 在文件目录中,表示父级目录(上级目录),也是以当前文件的位置作为参考值
/目录/文件名 顶级目录下(顶级路径下)
./1.txt 当前目录下的1.txt文件
../2.txt 父级目录下的2.txt文件
../../2.txt 上2级目录下的2.txt文件
../file/2.txt 父级目录下的file目录下的2.txt文件
/2.txt 当前系统根目录(windows下表示当前系统盘符下)的2.txt
文件指针就是我们平时输入文件时,一直闪烁的竖线。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jh58h6fH-1689674077728)(assets/image-20220324110804555.png)]
访问模式 | 说明(模式后面的+号,可以访问模式达到增强的作用,补全缺少的文件操作,例如:r本身只能支持读取内容,不能写入的,但是r+就具有了读取文件和写入文件内容的功能) |
---|---|
r | read的缩写,默认模式,以只读方式打开文件,不能修改文件。如果该文件不存在,则抛出异常。文件的指针将会放在文件的开头。 |
w | write的缩写,以只写方式打开文件,只用于写入。如果该文件已存在则将其覆盖,如果源文件有内容则会被清空。如果该文件不存在,创建新文件。 |
a | append的缩写,以追加写入内容方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。如果该文件不存在,则抛出异常。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
注意:
# 打开/新建文件,文件名为: python.txt
f = open('python.txt', 'w')
# 关闭文件
f.close()
open函数执行的结果会产生一个file句柄对象。使用file句柄对象,我们就可以完成文件的读写,打开与关闭等操作了。
文件在计算机中就是一种信息资源,文件因为内部不同,作用不同,会存在不同的文件类型.
文件相对于计算机,就类似生活中我们和地下水资源的关系,我们需要水的话,必须要凿井,通过水管来取水。
文件对于我们用户而言,实际上也是摸不着,碰不到的,计算机要对文件进行操作,也需要一条虚拟水管的,这种虚拟的水管,在计算机中就称之为"管道对象", “句柄对象”, “连接”, “通道”
file = open("./1.txt", "w")
print(file, type(file))
# <_io.TextIOWrapper name='./1.txt' mode='w' encoding='cp936'> <class '_io.TextIOWrapper'>
屬性名 | 描述 |
---|---|
file.name | 获取当前打开文件的文件名 |
file.closed | 获取当前文件的关闭状态 |
file.mode | 获取当前打开文件的访问模式 |
# 使用对象的属性,后面不需要小括号
file = open("./1.txt", "w")
print(file.name) # ./1.txt, 打开的文件名
print(file.mode) # w 打开的文件的访问模式
print(file.closed) # False, 查看文件的关闭状态,False表示没关闭
file.close()
print(file.closed) # True, 表示当前文件已经关闭了管道
方法 | 描述 |
---|---|
file.write(str: string) | 写入文件内容,将字符串或二进制数据写入被打开的文件。 |
file.writelines(seq) | 把列表中的成员数据写入到文件中,就是多行一次性写入 |
file.read([n=-1]) | 读取文件内容,读取出来的内容是字符串也可以是二进制数据。读取过程中,如果设置了n,则最多读取文件中的n个字符,如果没有设置则默认为-1,则默认读取文件中的全部内容字符。 |
file.readline([limit=-1]) | 读取文件的一行内容,如果设置了limit,有可能返回的只是一行的limit个字符。如果没有设置则默认读取整行内容。 |
file.readlines() | 按行读取整个文件内容,以列表格式返回,列表的成员是文件的每一行内容。 |
file.tell() | 获取当前文件中读写数据的光标(指针)所在位置。 1. 基于r、r+、w、w+模式打开文件,默认位置是0,表示文件开头 2. 基于a或a+模式打开的文件,默认值是文件内容的末尾下标位置。 3. 刚执行完file.read()的文件,光标所在位置,是在file.read()读写内容的后面位置。 |
file.seek(offset: int) | 设置文件读写数据的光标(指针)到指定的offset指定位置。 |
file.truncate(size: int = None) | 把文件裁成指定大小。文件必须以写方式打开,但w和w+除外。 |
file.flush() | 把缓冲区的内容写入硬盘的文件中。默认情况下,程序写入内容到文件中,并不是逐行代码逐行写入,而是在运行过程中把写入文件的数据先保存到了内存的缓冲区中。 |
file.writable() | 判断当前打开文件是否可写。 |
file.readable() | 判断当前打开文件是否可读。 |
""" 写入数据 file.write(string | bytes) # 把字符串/bytes类型数据写入到文件中 file.writeline(seq) # 把序列类型中数据逐行写入到文件(序列类型中的成员必须是字符串) """ # 写入一个数据(字符串/bytes) # file = open("6.txt", "w") # file.write("hello") # file.close() # 写入二进制数据,文本也可以转换成二进制写入,但是工作中更多的是图片/网络信息/视频/音频/压缩包等二进制比较多 # file = open("6.txt", "wb") # file.write("hello world".encode()) # file.close() # 写入文件中的数据,如果是其他格式,最好先转换成字符串/bytes类型以后再写入,工作中,一般使用json/base64的格式写入 # file = open("6.txt", "w") # file.write({"id":100}) # file.close() """扩展: json json.dumps() # 把列表/字典/元组转换成一个json编码格式字符串 json.loads() # 把一个json编码格式字符串还原成字典或者列表 """ # # 把一个非字符串的数据(列表/字典/元组)写入文件中 # import json # file = open("6.txt", "w") # data = {"id": 1, "name":"xiaoming"} # # data = [{"id": 1, "name":"xiaoming"}] # # data = (1,2,3) # content = json.dumps(data) # print(content, type(content)) # file.write(content) # # # 把上面的内容从文件中提取还原 # import json # file = open("6.txt", "r") # content = file.read() # print(content, type(content)) # data = json.loads(content) # print(data, type(data)) """扩展:base64 base64.b64encode() # 把其他任意数据类型转换成字符串 base64.b64decode() # 把bas64编码类型的字符串还原成原有格式数据 """ # base64可以转换一切数据格式成字符串 # import json, base64 # file = open("6.txt", "w") # data = {"id": 1, "name":"xiaoming"} # # data = [{"id": 1, "name":"xiaoming"}] # # data = (1,2,3) # byte_data = json.dumps(data).encode() # content = base64.b64encode(byte_data).decode() # print(content, type(content)) # file.write(content) # # 把上面的内容从文件中提取还原 # import json, base64 # file = open("6.txt", "r") # content = file.read() # # print(content, type(content)) # data = base64.b64decode(content).decode() # print(data, type(data)) # {"id": 1, "name": "xiaoming"} <class 'str'> # dict_data = json.loads(data) # print(dict_data) # {'id': 1, 'name': 'xiaoming'} """把序列类型中的数据逐行写入""" # # 使用write把列表中的数据逐行写入 # data = ["君不见黄河之水天上来②,奔流到海不复回。", "君不见高堂明镜悲白发③,朝如青丝暮成雪④。", "人生得意须尽欢⑤,莫使金樽空对月⑥。"] # file = open("7.txt", "w", encoding="utf-8") # for item in data: # file.write(f"{item}\n") # file.close() # data = ["君不见黄河之水天上来②,奔流到海不复回。\n", "君不见高堂明镜悲白发③,朝如青丝暮成雪④。\n", "人生得意须尽欢⑤,莫使金樽空对月⑥。\n"] # file = open("7.txt", "w", encoding="utf-8") # file.writelines(data) # file.close() """ 读取数据 file.read(n=-1) # 读取文件所有内容,如果有指定参数选项n,则表示本次读取数据只读取n个字符 file.readline() # 读取文件的一行内容 """ """按字符串读取文件内容""" # file = open("7.txt", "r", encoding="utf-8") # data = file.read(5) # 本次读取5个字符 # print(data) # data = file.read(15) # print(data) # 在上一次的进度上,再次读取5个字符 # data = file.read() # print(data) # 读取剩余内容的全部 # file.close() """按行读取文件内容""" # file = open("7.txt", "r", encoding="utf-8") # content = file.readline() # print(content) # content = file.readline() # print(content) # content = file.readline() # print(content) # 读取大文件可以使用这个方式 # file = open("7.txt", "r", encoding="utf-8") # while True: # content = file.readline() # if not content: # 切记:要加判断,如果读不到内容了就退出循环 # break # print(content) """一次性把文件所有内容以列表方式,逐行读取返回""" # # 大文件千万不要这么读取, 小文件可以 # file = open("7.txt", "r", encoding="utf-8") # print( file.readlines() ) # ['君不见黄河之水天上来②,奔流到海不复回。\n', '君不见高堂明镜悲白发③,朝如青丝暮成雪④。\n', '人生得意须尽欢⑤,莫使金樽空对月⑥。\n']
字符在不同编码文件下,长度是不一致的。
ASCII码—> 就所有大小写字母,数字
0100 0001 --> 65 —> A
0110 0001 --> 97 —> a
1个字节长度可以表达的数字:1111 1111(-127) ~ 0111 1111(127)
所以ASCII码中所有字符只需要一个字节长度(8bit)就全部保存下来了。
因为一个字符长度已经被ascii全部使用完了,所以其他国家的文字/字符就只能使用2个字符长度
2个字节长度可以表达的数字:1111 1111 1111 1111(-32767) ~ 0111 1111 1111 1111(32767)
日文jp、韩文kr、中文简体gbk,中文繁体big5
所以gbk编码下,1个中文就是2个字节长度
因为长期如果每一个国家地区都是自己独立的编码文件,那么针对国际化过程中,出现一些多语言的项目就会出问题。
为了满足跨语言、跨平台进行文本编码转换、处理的要求,所以国际组织制定一套可以容纳世界上所有文字和符号的字符编码方案,
这个方案就是unicode编码,也叫国际码、统一码。
3个字节长度:1111 1111 1111 1111 1111 1111(-8388607) ~ 0111 1111 1111 1111 1111 1111(8388607)
unicode编码随着时间的推移,还在不断的收录更多的文字/字符,不仅中文还有其他语言的文字。
UTF-8(少收录部分偏僻中文)
utf-8mb4(再次扩充了中文字符)
注意:utf-8属于unicode编码集合,但是utf-8编码中也保存ascii编码的,同时gbk编码中也是包含ascii。
事实上而言,不管gbk还是utf-8都是在ascii的基础上扩充开来的。
""" 文件操作过程中的指针(光标)管理 file.tell() # 查看当前文件中指针位置 file.seek(offset) # 控制移动当前文件中指针的位置 """ # r模式打开文件,指针在开头 # w模式打开文件,指针在开头 # a模式打开文件,指针在末尾 # file = open("8.txt", "r", encoding="utf-8") # point = file.tell() # 读取文件指针位置,不会影响文件指针的位置 # print(point) # 0 # content = file.read(5) # 读取5个字符,读取/写入数据到文件时,文件指针会随着操作而移动 # print(content) # 君不见黄河 # point = file.tell() # print(point) # 15 ctrl+D 复制光标所在 ctrl+x 剪切光标所在行 # content = file.read(5) # print(content) # 之水天上来 """ 上面读取了5个中文以后,文件指针从0移动到了15,原因是因为文件指针是按照字符本身在编码中的字节长度来计算的。 """ # file = open("8.1.txt", "r", encoding="gbk") # point = file.tell() # 读取文件指针位置,不会影响文件指针的位置 # print(point) # 0 # content = file.read(5) # 读取5个字符,读取/写入数据到文件时,文件指针会随着操作而移动 # print(content) # 君不见黄河 # point = file.tell() # print(point) # 10 ctrl+D 复制光标所在 ctrl+x 剪切光标所在行 # content = file.read(5) # print(content) # 之水天上来 """使用seek在操作文件过程中移动指针的位置""" # 例如,以a+模式打开一个文件,就可以对文件进行读写,但是因为a模式的原因,指针会在文件末尾。 # 此时,如果希望让指针回到最开始位置,就可以使用seek file = open("8.txt", "a+", encoding="utf-8") content = file.read() print(content) point = file.tell() print(point) # 183 # 把指针位置移动到文件开头 file.seek(0) point = file.tell() print(point) # 0 content = file.read(5) print(content) # 君不见黄河 point = file.tell() print(point) # 15 # 再次把指针位置移动到文件开头 file.seek(0) point = file.tell() print(point) # 0 content = file.read(5) print(content) # 君不见黄河 point = file.tell() print(point) # 15 # a+模式可以让我们写入内容,因为a模式属于追加内容的原因,所以如果写入内容,则内容会被追加文件末尾 content = "(又大又长的黄河)" file.write(content) point = file.tell() print(point) # 229
所谓缓冲区,就是内存空间的一部分,这部分空间只保存程序运行过程中的输入和输出数据。
""" 在文件操作过程中,因为内存中的信息处理速度要远远高于硬盘设备的处理速度, 所以如果内存中程序运行的结果如果和硬件处理速度保持一致,就会让内存/CPU存在极大浪费 所以,内存中高速运行程序时,会把程序执行的结果保存到内存的暂存区域(缓冲区)里面。 硬件设置会自动往暂存区域里面提取程序的结果。 """ # file = open("10.1.txt", "w") # file.write("hello") # # "hello"这段文件目前还在缓冲区里面,所以我们如果打开文件, # # 在文件管道对象关闭之前,是看不到上面的"hello" # # input("让程序等到用户输入内容以后才结束") # file.close() # 默认情况下,只有在关闭文件管道对象时,才会把程序运行的结果冲刷出缓冲区, # 如果出现程序运行到上面时,系统断电等问题,则会造成数据丢失。 """ 如果希望程序运行的结果,快速从缓冲区里面把数据冲刷出来。 可以使用file.flush() """ file = open("10.1.txt", "w") file.write("hello") input("让程序停顿一下") file.flush() # 冲刷缓存区,让数据不需要等待程序执行结束也可以提前写入到文件中。 file.write(" world") input("让程序停顿一下") file.close() # 默认情况下,只有在关闭文件管道对象时,才会把程序运行的结果冲刷出缓冲区
在以下几种情况下系统会刷新缓冲区的数据出来
1. 当文件关闭的时候自动刷新缓冲区
2. 当整个程序运行结束的时候自动刷新缓冲区
3. 当缓冲区写满了,也会自动刷新缓冲区
4. 手动刷新缓冲区 file.flush()就是手动调用
with语句也叫上下文管理器,使用上下文管理器,可以在读写文件的时候,只需要关注于操作文件的代码编写,而不需要在意文件是否关闭了,因为with语句块在执行完以后,会自动帮我们执行file.close()方法,关闭文件。
语法如下:
with 表达式 [as 变量]:
代码块
代码:
file = open("1.txt", "w+", encoding="utf-8")
print(file.closed) # False
file.close()
print(file.closed) # True
with open("2.txt", "w+", encoding="utf-8") as f: # 相当于 f=open()
pass
print( f.closed ) # True
# wb rb 模式的使用
# 将字符串和字节流(Bytes流)类型进行转换 (参数写成转化的字符编码格式)
# encode() 编码 将字符串转化为字节流(Bytes流)
# decode() 解码 将Bytes流转化为字符串
strvar = "二进制数据" strvar1 = "二进制数据".encode("utf-8") # print(strvar1) res = strvar1.decode("utf-8") # print(res) # 在b模式,不要指定encoding 有语法错误 # 把二进制字节流写入到文件当中 strvar = "二进制数据" fp = open("3.txt",mode="wb") str1 = strvar.encode("utf-8") fp.write(str1) fp.close() # 把二进制字节流读取出来 fp = open("3.txt",mode="rb") res = fp.read() fp.close() print(res) str2 = res.decode("utf-8") print(str2)
# 读取图片操作
fp = open("集合.png",mode="rb")
res = fp.read()
fp.close()
# print(res)
# 写入图片操作
fp = open("集合-备份.jpg",mode="wb")
fp.write(res)
fp.close()
with open("12.txt", "w") as f:
ret = f.writable() # True表示可写入数据到文件中
print(ret) # True
ret = f.readable() # True表示可读取文件中的数据,False表示不能
print(ret) # False
backup_file_name = input("请输入你要备份的文件名:") with open(backup_file_name, 'rb') as backup_file: # 提取文件的后缀 index = backup_file_name.rfind(".") if index > 0: ext = backup_file_name[index:] # .txt # 定义新的文件名 new_file_name = f"{backup_file_name[:index]}[备份]{ext}" # print(new_file_name) # 根据新的新文件名新建文件 with open(new_file_name, 'wb') as new_file: # 把旧文件中的数据,一行一行的进行复制到新文件中 while True: line = backup_file.readline() if not line: break new_file.write(line)
import json """ 学生信息管理系统 功能:查看学生数据列表,能修改学生数据,能删除数据,能新增数据,能退出管理系 """ # 学生信息的存储列表 student_list = [] """ 文件存储内容的格式方案1【最复杂】: 姓名:小名|年龄:25|性别:男|手机号码:1331234566 姓名:小名|年龄:25|性别:男|手机号码:1331234566 姓名:小名|年龄:25|性别:男|手机号码:1331234566 文件存储内容的格式方案2【最简单,最常用】: 通过上午扩展时了解的json 文件存储内容的格式方案3【其次】: 通过上午扩展时了解的json+base64 """ """先到文件中读取数据保存变量student_list中""" # 注意:第一次使用,手动创建这个文件,以后可以通过 os模块提供的操作,就可以判断该文件是否存在 with open("student.txt", "r") as f: content = f.read() if content: student_list = json.loads(content) while True: """1. 显示菜单""" print("* " * 15) print("* 欢迎来到XX学生信息管理系统。") print("*") print("* 1. 添加学生信息") print("* 2. 查看学生信息") print("* 3. 修改学生信息") print("* 4. 删除学生信息") print("* 5. 退出信息系统") print("* " * 15) print() action = int(input("请输入要进行的操作序号(1·5):")) if action == 1: print("请输入要录入系统的学生信息...") name = input("姓名:") age = input("年龄:") sex = input("性别:") mobile = input("联系电话:") # 把学生信息往student_list进行追加 student_list.append({ "name": name, "age": age, "sex": sex, "mobile": mobile, }) print(f"student_list={student_list}") elif action == 2: for index, item in enumerate(student_list): print(f"序号: {index+1}\t\t姓名: {item['name']}\t\t年龄: {item['age']}\t\t性别: {item['sex']}\t\t联系电话: {item['mobile']}") print("- " * 15) elif action == 3: for index, item in enumerate(student_list): print(f"序号: {index+1}\t\t姓名: {item['name']}\t\t年龄: {item['age']}\t\t性别: {item['sex']}\t\t联系电话: {item['mobile']}") print("- " * 15) num = int(input("请输入要更新的学生信息序号(如果部分信息不修改,可以不填写留空):")) name = input(f"姓名({student_list[num-1]['name']}):") age = input(f"年龄({student_list[num-1]['age']}):") sex = input(f"性别({student_list[num-1]['sex']}):") mobile = input(f"联系电话({student_list[num-1]['mobile']}):") # 更新数据 data = student_list[num-1] # data与student_list[num-1]是引用关系,所以data被改动,就表示student_list[num-1]被改动了 if name: data["name"] = name if age: data["age"] = age if sex: data["sex"] = sex if mobile: data["mobile"] = mobile elif action == 4: for index, item in enumerate(student_list): print(f"序号: {index+1}\t\t姓名: {item['name']}\t\t年龄: {item['age']}\t\t性别: {item['sex']}\t\t联系电话: {item['mobile']}") print("- " * 15) text = input("请输入要删除的学生信息序号(如果要一次性删除多个,序号之间使用空格隔开):") num_list = text.split(" ") for num in num_list: print(num, type(num)) # num还是字符串类型,需要转换成整数 num = int(num) student_list.pop(num-1) # num是从1开始,给用户看的,但是删除数据要使用下标,因此num-1 else: # 如果有学生数据,则保存数据到文件中 if len(student_list) > 0: content = json.dumps(student_list) # 把列表转换成字符串 with open("student.txt","w") as file: file.write(content) print("成功退出系统中....") break print() print()
上面代码有个bug,是列表数据正序删除时出现的,所以要把代码改成逆序删除。这是作业。
1. open打开文件的写法, 2. 常用的几种访问模式 r r+ rb rb+ w wb wb+ a 3. 基于with语句操作文件,会自动关闭文件 4. 文件对象的常用操作 file.read() file.readline() file.write() file.tell() file.seek() file.flush() 5. 编码字节长度的问题 1个字节长度 = 8bit---> 0000 0000 中文: utf-8: 1个字符长度 = 3个字节长度 gbk : 1个字符疮毒 = 2个字节长度 字母/数字/富豪 1个字符长度 = 1个字节长度
1. json的简单使用 import json # 字典/列表 转换成字符串 json.dumps(字典/列表) json.loads(字符串) 2. base64的简单使用 import base64 base64.b64encode() # 编码 base64.b64decode() # 解码 3. 缓冲区的概念,冲刷缓冲区 内存中高速运行程序时,会把程序执行的结果保存到内存的暂存区域(缓冲区)里面。 file.flush() 4. 哪几种情况下系统会刷新缓冲区的数据出来 1. 程序结束 2. 缓冲区满了 3. 手动冲刷 4. 关闭文件
1. 使用file.close()关闭文件
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。