人工智能(AI)基础入门之文件操作篇
本章学习目标
• 理解文件的概念
• 掌握文件的操作
• 掌握目录的操作
程序在运行时将数据加载到内存中,内存中的数据是不能永久保存的,这时就需要将数据存储起来以便后期多次使用,通常是将数据存储在文件或数据库中,而数据库最终还是要以文件的形式存储到介质上,因此掌握文件处理是十分有必要的。
12.%2 文件概述
读者对文件并不陌生,它可以存储文字、图片、音乐、视频等,如图12.1所示。总之,文件是数据的集合,可以有不同的类型。
图12.1 各种不同类型的文件
按数据的组织形式,文件大致可以分为两类,具体如下所示:
1. 文本文件
文本文件是一种由若干字符构成的文件,可以用文本编辑器进行阅读或编辑。以txt、py、html等为后缀的文件都是文本文件。
2. 二进制文件
二进制文件一般是指不能用文本编辑器阅读或编辑的文件。以mp3、mp4、png等为后缀的文件都是二进制文件,如果想要打开或修改这些文件,必须通过特定软件进行,比如用Photoshop软件可以编辑图像文件。
从本质上讲,文本文件也是二进制文件,因为计算机处理的全是二进制数据。
12.%2 文件操作
通过程序操作文件与手动操作文件类似,通常需要经过三个步骤:打开文件、读或写数据、关闭文件。
12.2.1 打开文件
对文件所有的操作都是在打开文件之后进行的,打开文件使用open()函数来实现,其语法格式如下:
open(file[, mode = 'r' [,...]])
该函数返回一个文件对象,通过它可以对文件进行各种操作,另外参数列表中参数的说明如表12.1所示。
表12.1 open()函数的各参数说明
参数 |
说明 |
file |
被打开的文件名 |
mode |
文件打开模式,默认是只读模式 |
例如打开文件名为test.txt文件,具体示例如下:
f1 = open('test.txt') # 打开当前目录下的test.txt文件
f2 = open('../test.txt') # 打开上级目录下的test.txt文件
f3 = open('D:/1000phone/test.txt') # 打开D:/1000phone目录下的test.txt文件
示例中使用open()函数打开文件时使用只读模式打开,此时必须保证文件是存在的,否则会报文件不存在的错误。
Python中打开文件的模式有多种,具体如表12.2所示。
表12.2 文件打开模式
mode |
权限 |
读/写格式 |
删除原内容 |
文件不存在 |
文件指针初始位置 |
||
读 |
写 |
追加 |
|||||
'r' |
√ |
|
|
文本 |
|
产生异常 |
文件开头 |
'r+' |
√ |
√ |
|
文本 |
|
产生异常 |
文件开头 |
'rb+' |
√ |
√ |
|
二进制 |
|
产生异常 |
文件开头 |
'w ' |
|
√ |
|
文本 |
√ |
新建文件 |
文件开头 |
'w+' |
√ |
√ |
|
文本 |
√ |
新建文件 |
文件开头 |
'wb+' |
√ |
√ |
|
二进制 |
√ |
新建文件 |
文件开头 |
'a' |
|
|
√ |
文本 |
|
新建文件 |
文件末尾 |
'a+' |
√ |
√ |
√ |
文本 |
|
新建文件 |
文件末尾 |
'ab+' |
√ |
√ |
√ |
二进制 |
|
新建文件 |
文件末尾 |
在表12.2中,'r'表示从文件中读取数据,'w'表示往文件中写入数据,'a'表示往文件中追加数据,'+'可以与以上三种模式('r'、'w'、'a')配合使用,表示同时允许读和写。另外,当需要处理二进制文件时,则需要提供'b'给mode参数,例如'rb'用于读取二进制文件。
12.2.2 关闭文件
当对文件内容操作完以后,一定要关闭文件,这样才能保证所修改的数据保存到文件中,同时也可以释放内存资源供其他程序使用。关闭文件的语法格式如下:
文件对象名.close()
接下来演示文件的打开与关闭,如例12-1所示。
例12-1
1 f = open('test.txt', 'a+') # 以追加模式读写test.txt
2 f.close() # 关闭文件
运行结果如图12.2所示。
图12.2 运行结果
在例12-1中,通过open()函数打开文件test.txt,此时返回一个文件对象并赋值给f,最后通过文件对象调用close()方法关闭文件。
此处需注意,即使使用了close()方法,也无法保证文件一定能够正常关闭。例如,在打开文件之后和关闭文件之前发生了错误导致程序崩溃,这时文件就无法正常关闭。因此,在管理文件对象时推荐使用with关键字,可以有效地避免这个问题,具体示例如下:
with open('test.txt', 'r+') as f:
# 通过文件对象f进行读写操作
使用with-as语句后,就不需要再使用close()方法,另外with-as语句还可以打开多个文件,具体示例如下:
with open('test1.txt', 'r+') as f1, open('test2.txt', 'a+') as f2:
# 通过文件对象f1、f2分别操作test1.txt、test2.txt文件
从上述示例中可看出,with-as语句极大的简化了文件打开与关闭,这对保持代码的优雅性是有极大帮助的。
12.2.3 读文本文件
打开文件成功后将返回一个文本对象,对文件内容的读取可以通过该对象来实现,该对象有三种方法可以获取文件内容,具体如下所示:
1. read()方法
read()方法可以从文件中读取内容,其语法格式如下:
文件对象.read([size])
该方法表示从文件中读取size个字节或字符作为结果返回,如果省略size,则表示读取所有内容,如例12-2所示。
例12-2
1 with open('test.txt') as f:
2 str1 = f.read(4) # 读取4个字符
3 str2 = f.read() # 读取剩余所有字符
4 print(str1, str2, sep = '\n')
若test.txt文件内容如图12.3所示。
图12.3 test.txt文件内容
程序运行结果如图12.4所示。
图12.4 运行结果
在例12-2中,使用with-as语句打开test.txt文件,先读取4个字符组成字符串('千锋教育')并赋给str1,接着再读取剩余的字符串赋给str2。
2. readlines()方法
readlines()方法可以读取文件中的所有行,其语法格式如下:
文件对象.readlines()
该方法将文件中的每行内容作为一个字符串存入列表中并返回该列表,如例12-3所示。
例12-3
1 with open('test.txt') as f:
2 str = f.readlines() # 读取所有行内容
3 print(str)
运行结果如图12.5所示。
图12.5 运行结果
在例12-3中,第2行使用readlines()方法读取文件test.txt中每行内容并存入列表中。此处需注意,readlines()方法一次性读取文件中的所有行,如果文件很大,使用readlines()方法就会占用大量的内存空间,读取的过程也较长,因此不建议对大文件使用该方法。
3. readline()方法
readline()方法可以逐行读取文件的内容,其语法格式如下:
文件对象.readline()
该方法将从文件中读取一行内容作为结果返回,如例12-4所示。
例12-4
1 with open('test.txt') as f:
2 while True:
3 str = f.readline() # 读取一行内容
4 if not str: # 若没读取到内容,则退出循环
5 break
6 print(str, end = '') # 若读取到内容,则打印内容
运行结果如图12.6所示。
图12.6 运行结果
在例12-4中,通过while循环每次从文件中读取一行,当没读取到内容时,退出循环。
4. in关键字
除了上述几种方法外,还可以通过in关键字读取文件,如例12-5所示。
例12-5
1 with open('test.txt') as f:
2 for line in f:
3 print(line, end = '')
运行结果如图12.7所示。
图12.7 运行结果
在例12-5中,通过for循环每次从文件中读取一行,当没读取到内容时,退出循环。
12.2.4 写文本文件
文件中写入内容也是通过文件对象来完成,可以使用write()方法或writelines()方法来实现。
1. write()方法
write()方法可以实现向文件中写入内容,其语法格式如下:
文件对象.write(s)
该方法表示将字符串s写入文件中,如例12-6所示。
例12-6
1 with open('test.txt', 'w') as f:
2 f.write('扣丁学堂\n')
程序运行结束后,在程序文件所在路径下打开test.txt文件,其内容如图12.8所示。
图12.8 运行结果
在例12-6中,通过write()方法向test.txt文件中写入'扣丁学堂\n'。注意如果test.txt文件在打开之前存在,则先清空文件内容,再写入'扣丁学堂\n'。
2. writelines()方法
writelines()方法向文件中写入字符串列表,其语法格式如下:
文件对象.writelines(s)
该方法将列表s中的每个字符串元素写入文件中,如例12-7所示。
例12-7
1 s = ['千锋教育', '扣丁学堂', '好程序员特训营']
2 with open('test.txt', 'w') as f:
3 f.writelines(s)
程序运行结束后,在程序文件所在路径下打开test.txt文件,其内容如图12.9所示。
图12.9 运行结果
在例12-7中,通过writelines ()方法将列表s中的元素写入test.txt文件,注意写入的字符串之间没有换行。
12.2.5 读写二进制文件
文本文件使用字符序列来存储数据,而二进制文件使用字节序列存储数据,它只能被特定的读取器读取。Python中pickle模块可以将数据序列化。
序列化是指将对象转化成一系列字节存储到文件中,而反序列化则相反,是指程序从文件中读取信息并用来重构上一次保存的对象。
pickle模块中dump()函数可以实现序列化操作,其语法格式如下:
dump(obj, file, [,protocol = 0])
该函数表示将对象obj保存到文件file中,参数protocol是序列化模式,默认值为0,表示以文本的形式序列化,protocol的值还可以是1或2,表示以二进制的形式序列化。
pickle模块中load ()函数可以实现反序列化操作,其语法格式如下:
load(file)
该函数表示从文件file中读取一个字符串,并将它重构为原来的python对象。
接下来演示使用pickle模块实现序列化和反序列化操作,如例12-8所示。
例12-8
1 import pickle # 导入pickle模块
2 data1 = {'小千': [18, '女', 100],
3 '小锋': [19, '男', 98.5],
4 '小扣': [18, '男', 60] }
5 data2 = ['千锋教育', '扣丁学堂', '好程序特训营']
6 with open('test.dat', 'wb') as f1:
7 pickle.dump(data1, f1) # 将字典序列化
8 pickle.dump(data2, f1, 1) # 将列表序列化
9 with open('test.dat', 'rb') as f2:
10 data3 = pickle.load(f2) # 重构字典
11 data4 = pickle.load(f2) # 重构列表
12 print(data3, data4)
运行结果如图12.10所示。
图12.10 运行结果
在例12-8中,第7、8行通过dump()函数将data1与data2进行序列化后写入test.dat文件中,第10、11行通过load()函数从文件test.dat中读取数据并进行反序列化操作。
12.2.6 定位读写位置
文件指针是指向一个文件的指针变量,用于标识当前读写文件的位置,通过文件指针就可对它所指的文件进行各种操作。
tell()方法可以获取文件指针的位置,其语法格式如下:
文件对象.tell()
该方法返回一个整数,表示文件指针的位置,如例12-9所示。
例12-9
1 with open('test.txt', 'w+') as f:
2 n = f.tell() # 文件指针指向文件头,值为0
3 print(n)
4 f.write('www.qfedu.com')
5 n = f.tell() # 文件指针指向文件尾
6 print(n)
运行结果如图12.11所示。
图12.11 运行结果
在例12-9中,第2行获取文件指针位置为0,表示处于文件头,第4行向文件中写入字符串'www.qfedu.com',长度为13,此时文件指针处于文件尾。
seek()方法可以移动文件指针位置,其语法格式如下:
文件对象.seek((offset[, where = 0]))
其中,参数offset表示移动的偏移量,单位为字节,其值为正数时,文件指针向文件尾方向移动,其值为负数时,文件指针向文件头方向移动。参数where指定从何处开始移动,其值可以为0、1、2,具体含义如下所示:
• 0:表示文件头
• 1:表示当前位置
• 2:表示文件尾
接下来演示seek()方法的使用,如例12-10所示。
例12-10
1 with open('test.txt', 'w+') as f:
2 print(f.tell()) # 文件指针处于文件头
3 f.write('qfedu/com')
4 print(f.tell()) # 文件指针处于文件尾
5 f.seek(5,0) # 文件指针处于位置5
6 print(f.tell())
7 f.write('.')
8 print(f.tell())
运行结果如图12.12所示。
图12.12 运行结果
程序运行结束后, test.txt文件内容如图12.13所示。
图12.13 test.txt文件内容
在例12-10中,通过移动文件指针将“/”替换为“.”。
12.2.7 复制文件
在日常生活中,文件经常需要从一个路径下复制到另一个路径下。在Python中,shutil模块的copy()函数可以实现复制文件,其语法格式如下:
shutil.copy(src, dst)
该函数表示将文件src复制为dst,如例12-11所示。
例12-11
1 import shutil # 导入shutil模块
2 shutil.copy('D:/1000phone/test.txt', 'copytest.txt')
程序运行结束后,在目录“D:/1000phone/”会生成一个copytest.txt文件。
12.2.8 移动文件
在日常生活中,文件经常需要从一个路径下移动到另一个路径下。在Python中,shutil模块的move ()函数可以实现复制文件,其语法格式如下:
shutil.move(src, dst)
该函数表示将文件src移动到dst,如例12-12所示。
例12-12
1 import shutil # 导入shutil模块
2 shutil.move('D:/1000phone/copytest.txt', '../copytest.txt')
程序运行结束后,文件copytest.txt从目录“D:/1000phone/”移动到目录“D:/”。
12.2.9 重命名文件
在Python中,os模块的rename()函数可以重命名文件,其语法格式如下:
os.rename(src, dst)
该函数表示将src重名为dst,如例12-13所示。
例12-13
1 import os # 导入os模块
2 os.rename('D:/copytest.txt', 'D:/copytest1.txt')
程序运行结束后,文件copytest.txt被重名为“copytest1.txt”。
12.2.10 删除文件
在Python中,os模块的remove ()函数可以删除文件,其语法格式如下:
os.remove(src)
该函数表示将文件src删除,如例12-14所示。
例12-14
1 import os # 导入os模块
2 os.remove('D:/copytest1.txt')
程序运行结束后,文件copytest1.txt被删除。
12.%2 目录操作
在开发中,随着文件数量的增多,就需要创建文件夹来管理文件,本节讲解有关文件目录的操作,该操作需要导入os模块。
12.3.1 创建目录
os模块的mkdir()函数可以创建目录,其语法格式如下:
os.mkdir(path)
参数path指定要创建的目录,如例12-15所示。
例12-15
1 import os # 导入os模块
2 os.mkdir('D:/1000phone/codingke')
程序运行结束后,在目录“D:/1000phone/”创建出一个目录“codingke”。此处需注意该函数只能创建一级目录,如果需要创建多级目录,则可以使用makedirs()函数,其语法格式如下:
os.makedirs(path1/path2…)
参数path1与path2形成多级目录,具体示例如下:
import os # 导入os模块
os.makedirs('D:/1000phone/goodprogrammer/test')
程序运行结束后,目录结构为D:/1000phone/goodprogrammer/test。
12.3.2 获取目录
os模块的getcwd()函数可以获取当前目录,其语法格式如下:
os.getcwd()
该函数的使用比较简单,如例12-16所示。
例12-16
1 import os # 导入os模块
2 res = os.getcwd()
3 print(res)
运行结果如图12.14所示。
图12.14 运行结果
从程序运行结果可看出,本程序的文件在D:\1000phone目录中。
另外,os模块的listdir()函数可以获取指定目录中的内容,其语法格式如下:
os.listdir(path)
其中,参数path指定要获取内容目录的路径,如例12-17所示。
例12-17
1 import os # 导入os模块
2 res = os.listdir('D:/1000phone')
3 print(res)
运行结果如图12.15所示。
图12.15 运行结果
从程序运行结果可看出,该函数返回一个列表,其中的元素为D:/1000phone目录下所有文件名与目录名。
12.3.3 遍历目录
如果希望查看指定路径下全部子目录的所有目录和文件信息,就需要进行目录的遍历,os模块的walk()函数可以遍历目录树,其语法格式如下:
os.walk(树状结构文件夹名称)
该函数返回一个由3个元组类型的元素组成的列表,具体如下所示:
[(当前目录列表), (子目录列表), (文件列表)]
接下来演示使用walk()函数遍历目录,如例12-18所示。
例12-18
1 import os # 导入os模块
2 def traversals(path):
3 if not os.path.isdir(path):
4 print('错误:',path,'不是目录或不存在')
5 return
6 list_dirs = os.walk(path) # os.walk返回一个元组,包括3个元素
7 for root, dirs, files in list_dirs: # 遍历该元组的目录和文件信息
8 for d in dirs:
9 print(os.path.join(root, d)) # 获取完整路径
10 for f in files:
11 print(os.path.join(root, f)) # 获取文件绝对路径
12 traversals('D:\\1000phone')
程序运行结束后,输出D:/1000phone目录下全部子目录的所有目录和文件信息。
12.3.4 删除目录
删除目录可以通过以下两个函数,具体如下所示:
os.rmdir(path) # 只能删除空目录
shutil.rmtree(path) # 空目录、有内容的目录都可以删除
接下来演示这两个函数的使用,如例12-19所示。
例12-19
1 import os, shutil # 导入os、shutil模块
2 os.rmdir('D:/1000phone/codingke')
3 shutil.rmtree('D:/1000phone/goodprogrammer')
程序运行结束后, D:/1000phone/codingke空目录被删除,D:/1000phone/goodprogrammer目录及目录下内容被删除。
12.%2 小案例
在Windows操作系统中,查看某个文件目录信息可以通过鼠标右键选择属性,如图12.16所示。
图12.16 1000phone属性
在图12.16中,查看文件目录1000phone的属性,现要求编写程序,统计指定文件目录大小以及文件和文件夹数量,具体如例12-20所示。
例12-20
1 import os # 导入os模块
2 # 记录总大小、文件个数、目录个数
3 totalSize, fileNum, dirNum = 0, 0, 0
4 # 遍历指定目录
5 def traversals(path):
6 global totalSize, fileNum, dirNum
7 if not os.path.isdir(path):
8 print('错误:', path, '不是目录或不存在')
9 return
10 for lists in os.listdir(path):
11 sub_path = os.path.join(path, lists)
12 if os.path.isfile(sub_path):
13 fileNum += 1 # 统计文件数量
14 totalSize += os.path.getsize(sub_path) # 文件总大小
15 elif os.path.isdir(sub_path):
16 dirNum += 1 # 统计子目录数量
17 traversals(sub_path) # 递归遍历子目录
18 # 单位换算
19 def sizeConvert(size):
20 K, M, G = 1024, 1024**2, 1024**3
21 if size >= G:
22 return str(round(size/G, 2)) + 'GB'
23 elif size >= M:
24 return str(round(size/M, 2)) + 'MB'
25 elif size >= K:
26 return str(round(size/K, 2)) + 'KB'
27 else:
28 return str(size) + 'Bytes'
29 # 输出目录位置、大小及个数
30 def output(path):
31 if os.path.isdir(path):
32 print('类型;文件夹')
33 else:
34 return
35 print('位置:', path)
36 print('大小:', sizeConvert(totalSize) +
37 '('+ str(totalSize) + ' 字节)')
38 print('包含:', fileNum, '个文件, ',dirNum, '个文件夹')
39 # 测试
40 if __name__=='__main__':
41 path = 'D:/1000phone'
42 traversals(path)
43 output(path)
运行结果如图12.17所示。
图12.17 运行结果
从程序运行结果可看出,输出的信息与图12.16中的信息相同。
12.%2 本章小结
本章主要介绍了文件,包括文件概述、文件操作、目录操作。读者在实际编程中,注意区分文本文件与二进制文件的读写操作。另外,读者需重点掌握目录的操作。
12.%2 习题
1.填空题
(1) 文件分为文本文件与 。
(2) 打开文件可以使用 函数实现。
(3) 打开及关闭文件可以使用 语句实现。
(4) 方法可以获取文件指针的位置。
(5) 方法可以移动文件指针位置。
2.选择题
(1) 打开一个二进制文件并进行追加写入,正确的打开模式是( )。
A.'ab+' B.'a+'
C.'w+' D.'wb+'
(2) 下列选项中,用于读取文本文件一行内容的是( )。
A.文件对象.read() B.文件对象.readlines()
C.文件对象.readline() D.文件对象.read(300)
(3) os模块的( )函数可以删除文件。
A.move () B.del()
C.rename(): D.remove ()
(4) os模块的( )函数可以创建多级目录。
A.mkdir() B.make()
C.makedirs () D.makefiles()
(5) 下列选项中,( )只能删除空目录。
A.os.rmdir(path) B.shutil.rmtree(path)
C.os.rmtree(path) D.os.rmdir(path)
3.思考题
(1) 简述读取文本文件有哪些方法?
(2) 简述pickle模块中dump()函数与load ()函数的作用?
4.编程题
读取文本文件test.txt并生成文件newtest.txt,其中的内容与test.txt一致,但是在每行的首部添加了行号。
- 点赞
- 收藏
- 关注作者
评论(0)