在日常的程序开发过程中,经常需要将数据写入到文件中保存或者从文件中读取数据。Python内置了操作文件相关的函数,使得操作文件变得非常简单。本章将详细介绍常用的一些文件及文件夹相关操作。
9.1 读写文件
9.1.1 打开文件
在Python中操作一个文件,首先要使用内置的open函数打开该文件,返回一个文件对象,才能够对该文件进行操作。使用open函数打开文件可以设置三种常用模式,分别是只读模式(默认,使用字母r表示)、只写模式(使用字母w表示)、追加模式(使用字母a表示)。只读模式只用于读取文件内容,不能向文件中写入数据;只写模式用于将数据覆盖写入到文件中;只写模式用于将数据追加写入到文件的末尾。
例9-1 使用只读模式打开一个不存在的文件
案例代码如下:
f = open("test.txt","r") # 程序文件所在路径下没有test.txt文件
解析:使用“r”只读模式打开一个不存在的test.txt文件,则报文件不存在的错误。
例9-2 使用只写模式打开一个不存在的文件
案例代码如下:
f = open("test.txt","w")
解析:通过只写模式打开一个不存在的文件,如果没有指定文件路径,那么会在程序执行的当前路径下创建该文件。
总结:当打开一个不存在的文件时,只读模式会报FileNotFoundError,只写和追加两种模式都会创建一个新的空文件。当然,如果文件存在,这三种模式都会正常打开一个文件,open函数会返回一个文件对象,通过操作这个文件对象,读取文件内容或者向文件写入数据。
注意:在操作文件时,如果读取的文件内容包含中文或者写入到文件的数据包含中文,为了避免出现中文乱码,可以在open函数中设置打开文件的编码格式为encoding=“utf-8”。
9.1.2 写文件
1.write( )方法
Python内置的write( )方法可以将字符串数据写入到文件中。注意,使用write( )方法写入到文件中的内容不会自动换行。
如果使用只写模式“w”打开文件,那么write( )方法会采用覆盖写的方式将字符串数据写入文件。也就是说如果写入的文件不是一个空文件,那么会将原文件内容清空,然后写入新的内容。
例9-3 使用write( )方法向文件写入数据(“w”模式)
案例代码如下:
f = open("stunames.txt","w")
# 写入三个学生的名字
f.write("Tom")
f.write("David")
f.write("Carl")
解析:在stunames文件中写入了三个同学的名字,在写入时虽然调用了三次write( )方法,但是三个同学的名字还是挨着写的,没有换行。
再次采用同样的方式向stunames.txt文件写入学生姓名,将会覆盖原文件的内容。
f = open("stunames.txt","w")
# 写入三个学生的名字
f.write("Frank")
f.write("Harry")
再次打开stunames.txt文件,我们发现文件的内容已经被新写入的学生名字覆盖。
如果需要在原文件末尾追加数据而不是覆盖原有的内容,那么我们可以使用追加模式“a”打开文件。
例9-4 使用write( )方法向文件写入数据(“a”模式)
案例代码如下:
f = open("stunames.txt","a")
# 写入三个学生的名字
f.write("Tom")
f.write("David")
f.write("Carl")
解析:在原文件内容“FrankHarry”后追加了另外三个同学的名字。
使用write( )方法写入文件的数据,如果想实现换行写,可以在写入的数据中需要换行的地方加入换行符“\n”。
例9-5 使用write( )方法实现换行写
案例代码如下:
f = open("stunames.txt","w")
# 写入三个学生的名字
f.write("Tom\n")
f.write("David\n")
f.write("Carl\n")
解析:写入的每个学生名字后都会执行换行操作,从下一行开始写入新的学生名字。
2.writelines( )方法
调用一次write( )方法只能将一个字符串写入到文件中,如果想一次写入多个字符串就需要多次调用write( )方法。那么有没有一种简洁的方法,可以一次向文件中写入多个字符串呢?答案是肯定的,Python还提供了另外一个向文件中写入数据的writelines( )方法,writelines( )方法可以将一个序列中的多个字符串一次性写入到文件中。
例9-6 使用writelines( )方法一次写入多个字符串到文件中
案例代码如下:
f = open("stunames.txt","w",encoding="utf-8")
f.writelines(["张三\n","李四\n","王五\n"])
解析:writelines( )方法将一个列表中的多个字符串元素一次性地写入“stunames.txt”文件中。如果想实现换行写入,也要在待写入的每个字符串元素中加入换行符“\n”。
3.close( )方法
在日常的开发过程中,如果有操作数据库的需求,在通常情况下,操作完数据库要将数据的连接关闭或者将连接返回给连接池,这样做的好处是避免资源浪费,减少程序出错的风险。那么使用文件对象操作完文件,同样需要使用close( )方法关闭文件。如果不显示调用close( )方法关闭文件,在程序执行完也会自动关闭文件,操作系统会把待写入文件的数据缓存起来,如果此时由于某些原因操作系统崩溃,就会造成缓存的数据丢失,无法将缓存的数据写入到文件。所以在写代码时,当使用完一些资源,要对其释放或关闭,避免资源浪费,减少程序出错的风险。
对于例9-6来说,写完文件之后,文件对象通过调用close( )方法关闭文件。
f = open("stunames.txt","w",encoding="utf-8")
f.writelines(["张三\n","李四\n","王五\n"])
f.close() # 关闭文件
使用close( )方法显示关闭文件的方式是一种好的编码习惯,但总有些时候忘了调用close( )方法关闭文件,Python还给我们提供了一种安全打开文件的方式,就是使用“with”关键字配合open函数打开文件,通过这种方式,当操作完文件后程序会自动调用close( )方法,不需要显示地调用close( )方法,这种用法既简洁又安全。有关文件的操作,推荐使用with打开。
例9-7 使用with关键字安全打开关闭文件
案例代码如下:
with open("stunames.txt","w",encoding="utf-8") as f:
f.writelines(["张三\n","李四\n","王五\n"])
f.close() # 关闭文件
解析:在with的代码块内,open函数打开文件返回的文件对象通过as重命名为f,通过文件对象f操作文件,操作完文件程序自动关闭文件。
9.1.3 读文件
1.read( )方法
从文件中读取数据,可以调用Python内置的read( )方法。read( )方法可以一次性从文件中读取出所有文件内容。
例9-8 使用read( )方法读取stuname文件中所有学生名字
案例代码如下:
with open("stunames.txt","r",encoding="utf-8") as f:
data = f.read()
print(data)
2.readlines( )方法
Python内置的readlines( )方法可以按照行的方式把整个文件中的内容一次全部读取出来,返回结果的是一个列表,文件中的一行数据就是列表中的一个元素,由于文件中每行末尾包含一个不可见的换行符“\n”,所以列表中每一个元素的最后也包含一个换行符“\n”。
例9-9 使用readlines( )方法按行读取stuname文件中所有学生名字
案例代码如下:
with open("stunames.txt","r",encoding="utf-8") as f:
lines = f.readlines()
print(lines)
# 循环遍历lines,打印每行内容
for i in range(0,len(lines)):
print(f"第{i}行:{lines[i]}")
解析:我们发现打印出来的文件内容两行之间有一个空行,这是为什么呢?原因是print函数默认是换行打印,同时在文件内容的每行数据中包含一个换行符,这样造成两行之间多了一个空行,解决办法是:给print函数传入参数end=“”,取消print函数换行打印即可。
9.2 文件管理
在操作文件的时候,不只是读取文件内容或者向文件写入数据,还会涉及一些文件和文件夹相关的管理操作,例如:删除文件、文件重命名、创建文件夹等。本节将介绍一些常用的文件管理相关操作。
文件管理相关的操作需要引入Python内置的os模块,使用“import os”方式引入。
1.rename(oldfile,newfile)函数
Python内置的rename函数用于对文件或者文件夹重命名。注意:如果待操作的文件或文件夹不存在,执行rename函数则程序会报错。
例9-10 将文件“test.txt”重命名为“测试.txt”
案例代码如下:
import os
os.rename("test.txt","测试.txt")
解析:成功地将程序当前路径下的“test.txt”文件重命名为“测试.txt”。
注意:在执行重名文件的操作时,如果没有指定文件的绝对路径,那么会在程序执行的当前路径(相对路径)下查找文件。
2.remove(path)函数
Python内置的rename函数用于删除指定文件。
注意:在执行删除文件的操作时,如果没有指定文件的绝对路径,那么会在程序执行的当前路径(相对路径)下查找文件。
例9-11 删除当前路径下的“测试.txt”文件
案例代码如下:
import os
os.remove("测试.txt")
3.mkdir(path)函数
Python内置的mkdir函数用于在指定的路径下创建新文件夹。
import os
os.mkdir("d://testdir")
4.getcwd函数
Python内置的getcwd函数用于获取程序运行的绝对路径。
import os
print(os.getcwd())
5.listdir(path)函数
Python内置的listdir函数用于获取指定路径下的文件列表(包括文件和文件夹),函数返回值是一个列表。
例9-12 获取程序执行的当前路径下的文件列表
案例代码如下:
import os
lsdir = os.listdir("./")
print(lsdir)
6.rmdir(path)函数
Python内置的rmdir函数用于删除指定路径下的空文件夹。
注意:如果使用rmdir函数删除一个非空文件夹,程序将报错。
例9-13 删除程序执行的当前路径下的非空文件夹“datas”
案例代码如下:
import os
os.rmdir("./1、Python快速入门(8天零基础入门到精通)")
如果想删除一个非空文件夹,可以引入shutil模块的rmtree(path)函数。不建议在程序中直接删除一个非空文件夹,有可能会误删,最好确认无误后再删除。
9.3 JSON文件操作
JSON是一种轻量级的数据交换格式,使用得非常广泛。JSON数据格式与Python中的字典非常相似,也是以键值对的形式保存数据。但是,在JSON中每个键值对的键必须是字符串类型,值可以是多种类型,比如字符串、数字、列表、元组、字典等。JSON中的数据类型与Python中的数据类型会有一些差别,Python中的元组和列表在JSON中都是以列表形式存在,Python中的布尔类型True和Flase在JSON中会被转成小写的true和false,Python中的空类型None在JSON中会被转换成null。常见的JSON数据格式如图所示。
在Python中操作JSON格式数据要引入Python的json模块,json模块提供了丰富的操作JSON格式数据的函数,常用的几个函数如下:
- dumps(python_dict):将Python数据转换为JSON编码的字符串;
- loads(json_str):将JSON编码的字符串转换为Python的数据结构;
- dump(python_dict,file):将Python数据转换为JSON编码的字符串,并写入JSON文件;
- load(json_file):从JSON文件中读取数据,并将JSON编码的字符串转换为Python的数据结构。
1.dumps函数
例9-14 定义一个存储用户信息的字典,其中存储的数据格式是:姓名、年龄、编程语言(值是列表)、正在学习的课程(值是字典),是否是会员(值是布尔类型),性别未知使用空类型None表示。使用json模块的dumps函数将用户信息字典转换成JSON编码的字符串。
为了便于对比查看,下面使用JSON格式化工具将运行结果打印的字符串格式化成JSON格式,格式化结果如下:
从对比结果看,Python中的字典转换成JSON格式之后,其中的布尔类型True被转换成了true,空类型None被转换成了null。
2.loads函数
例9-15 使用loads函数将JSON编码的字符串转换为Python数据结构
案例代码如下:
3.dump函数
例9-16 使用dump函数将Python数据写入到JOSN文件
案例代码如下:
程序执行完成后,会在程序所在路径下创建一个“user_info.json”文件。
4.load函数
例9-17 使用load函数加载JSON文件,并将JSON文件中的数据转换成Python数据结构
案例代码如下:
9.4 CSV文件操作
相信大家对CSV格式文件已经非常熟悉,不管是在工作中还是生活中,经常会遇到CSV文件。在这里再简单介绍一下CSV文件,CSV文件内容默认使用逗号分隔,可以使用Excel打开,由于CSV文件是一种文本文件,所以还可以使用其他文本编辑器打开。CSV文件内的数据没有类型,所有数据都是字符串。
下面将通过示例来介绍在Python中是如何操作CSV文件的。
9.4.1 写入CSV文件
操作CSV文件需要先引入csv模块,在csv模块中提供了两个方法可以向CSV文件写入数据,分别是:
writerow([row_data]):一次写入一行数据;
writerows([[row_data],[row_data],…]):一次写入多行数据。
例9-18 将用户信息写入到CSV文件中
案例代码如下:
import csv
# 用户信息列表,嵌套列表内的每一个小列表是一行数据
datas = [["name","age"],["zhuangsan",20],["lisi",30]] # 嵌套列表内的第一个列表是标题
with open("./user_info.csv","w") as f:
# writer函数会返回一个writer对象,通过writer对象向CSV文件写入数据
writer = csv.writer(f)
# 循环遍历列表一次写入一行数据
for row in datas:
writer.writerow(row)
程序运行完会在程序执行的当前路径下创建一个“user_info.csv”文件。
在例9-17中我们使用for循环遍历列表数据,然后调用writer对象的writerow方法将每一行数据写入CSV文件中。如果要写入CSV文件的数据量很大,通过循环遍历的方式就会显得非常麻烦,而且效率低下,这时我们可以使用writerows方法一次性地将待写入的列表数据全部写入到CSV文件中。
改造上一个程序代码,去掉循环,使用writerows方法一次性地将数据写入CSV文件。
import csv
# 用户信息列表,嵌套列表内的每一个小列表是一行数据
datas = [["name","age"],["zhuangsan",20],["lisi",30]] # 嵌套列表内的第一个列表是标题
with open("./user_info.csv","w") as f:
# writer函数会返回一个writer对象,通过writer对象向CSV文件写入数据
writer = csv.writer(f)
writer.writerows(datas)
注意:如果向文件中写入中文,需要在open函数中设置文件编码格式为utf-8。
9.4.2 读取CSV文件
在csv模块中提供了读取CSV文件的reader方法,reader方法会根据打开的文件对象返回一个可迭代对象,然后遍历这个对象读取CSV文件中每一行数据。
例9-19 读取当前运行的程序文件所在路径下的user_info.csv文件,查看用户信息
案例代码如下:
import csv
with open("./user_info.csv","r",encoding="utf-8") as f:
reader = csv.reader(f) # 返回一个reader可迭代对象
for row in reader:
print(row) # row是一个列表
print(row[0]) # 通过索引获取列表中元素
print(row[1])
print("--------------------")
解析:第一行打印的是标题,接下来的每一次循环打印一条用户信息。