本文是Python通用编程系列教程,已全部更新完成,实现的目标是从零基础开始到精通Python编程语言。本教程不是对Python的内容进行泛泛而谈,而是精细化,深入化的讲解,共5个阶段,25章内容。所以,需要有耐心的学习,才能真正有所收获。虽不涉及任何框架的使用,但是会对操作系统和网络通信进行全局的讲解,甚至会对一些开源模块和服务器进行重写。学完之后,你所收获的不仅仅是精通一门Python编程语言,而且具备快速学习其他编程语言的能力,无障碍阅读所有Python源码的能力和对计算机与网络的全面认识。对于零基础的小白来说,是入门计算机领域并精通一门编程语言的绝佳教材。对于有一定Python基础的童鞋,相信这套教程会让你的水平更上一层楼。
一 文件读写基本操作
1. 文件操作的工作流程
文件在我们的计算机上随处可见,当我们需要永久保存数据的时候就会用到文件,文件是由计算机操作系统来提供的,那么自然也就受操作系统的控制。如下图所示,一套完整的计算机系统主要由三部分构成:
- 应用程序
- 操作系统
- 计算机底层硬件
2. 文件操作的基本形式
我们事先在当前路径下准备好一个文件a.txt,如下图所示:
接下来我们在 "文件处理.py" 文件内开始写打开读取文件的操作,在Python中必然会有一个功能或者接口来打开文件,这个接口就是open,使用参数如下图所示: 文件读取操作代码示例如下:"""open打开文件需要3个参数,打开文件之后会有一个返回值,读写操作就是对这个返回值进行操作f = open('文件的路径',mode='打开文件的模式',encoding='操作文件的字符编码')""""""open是向操作系统发请求,会占用操作系统资源,这个资源不会自动回收返回值就是应用程序拿到的变量,应用程序的变量Python解释器会自动帮你回收"""# 1 打开文件f = open(r'a.txt',mode='r',encoding='utf-8')"""对于应用程序来说上面这行代码与我写一个"f = 1"没有本质区别,你不需要再执行"del f",因为解释器会自动帮你清理这个应用程序资源,但是,打开的文件占用了操作系统的资源,这不会自动回收"""# 2 读取文件data = f.read()print(data)# 3 关闭文件,清理操作系统打开文件的资源f.close()print(f) # 应用程序的资源还在# f.read() # 文件关闭不能再进行读取复制代码
打开一个文件其实是占用了两部分资源,分别是操作系统资源和应用程序资源,应用程序资源会自动由Python解释器来回收,而操作系统打开文件的资源并不会立即回收,操作系统每打开一个文件其实会有一个编号,每个编号与应用程序向操作系统发起文件操作请求的编号一一对应,这个编号称为文件描述符,操作系统的文件描述符编号是有限的,所以,当服务器高并发的时候,由于打开文件个数非常多,因而还没来得及关闭,那么服务器就卡了,返回给用的的结果就是用户的客户端卡了。
有的时候关闭文件的操作总是会被遗忘,我们有一个使用 "with"来操作文件的方式,它是一个上下文的操作,会帮你自动的关闭文件,代码示例如下:
# as 指的是赋值with open('a.txt', 'r', encoding='utf-8') as f: data = f.read() print(data)复制代码
除此之外,“with” 可以连续打开多个文件,代码示例如下:
with open('a1.txt', 'r', encoding='utf-8') as f1, \ open('a2.txt', 'r', encoding='utf-8') as f2: data1 = f1.read() data2 = f2.read()复制代码
二 默认打开文件的参数说明
1. 文件打开的字符编码
如果不指定字符编码,默认打开文件的字符编码与操作系统相匹配:
- Windows系统(中国大陆用户):gbk
- Liunx系统:utf-8
- MacOS:utf-8
在不指定字符编码的情况下,MacOS系统示例代码:
# 文件保存的以utf-8编码保存,与本机默认编码一致with open('a.txt', 'r', ) as f: data = f.read() print(data)复制代码
2. 文件的打开模式
文件默认的打开模式是“t”模式,指的是文本模式,这意味着在该模式下无法打开图片,视频和音频等文件,因为这些是以二进制格式存储的,文本模式是以字符形式存储的。
操作文件的模式有三种,分别是:“r”,“w”和“a”模式,“r”是只读,“w”是只写,“a”是指追加,默认操作文件大模式是“r”模式,所以默认文件的打开模式是“rt”模式,对于操作文本文件,“t”模式必须与操作文件的三种模式连用,很多时候你看到的,这个“t”经常会省略不写,这是可以的。
三 文本模式打开文件的操作
1. 操作文件“r”模式
全部读取使用read,代码示例如下:
f = open('a.txt', mode='r', encoding='utf-8') # “r”模式下,如果文件不存在会报错# f.write('哈哈') #抛出异常,不能写print(f.readable()) # 判断是否可读print('=============>1')print(f.read()) # 全部读取print('=============>2')# 读文件会有一个光标移动,第一次读完了,光标移至末尾,第二次读无内容print(f.read())f.close()复制代码
一行一行读文件内容使用readline,代码示例如下:
f = open('a.txt', mode='r', encoding='utf-8')# readline指的是一行一行读文件print(f.readline(), end='') # 文件中有换行,print也自带换行,指定end参数去掉默认换行print(f.readline(), end='')print(f.readline(), end='')f.close()复制代码
全部读取文件内容,存入列表,每行内容为列表的一个元素使用readlines,代码示例如下:
f = open('a.txt', mode='r', encoding='utf-8')print(f.readlines()) f.close()复制代码
readlines可以加数字作为参数,但是他不是指的行数,而是字节数,所以我们一般不用,如需逐行打印文件内容常用readlines与for循环连用,代码示例如下:
# 如果文件内容比较少的时候,以下两种方式都可以with open('a.txt') as f: # 当文件很大时,f.readlines()结果是一个很大的列表在内存中,机器就卡了 for line in f.readlines(): print(line, end='')# 推荐使用这种方式with open('a.txt') as f: # f是一个可迭代对象,就像老母鸡会下蛋一样 for line in f: # 文件内容很大时,使用这种方式每次内存中只有一行内容 print(line, end='')复制代码
2. 操作文件“w”模式
注意:在“w”只写模式下,当文件存在时,就会清空该文件,代码示例如下:
f = open(r'a.txt', mode='w', encoding='utf-8') # 默认是wtf.write('第一行\n') # 需要自己添加“\n”来换行f.write('第二行\n')f.close()复制代码
当文件不存在时,就会创建空文档,代码示例如下:
f = open(r'a1.txt', mode='w', encoding='utf-8') # 默认是wtf.write('第一行\n')f.write('第二行\n')f.close()复制代码
只写模式常用的方法:
f = open(r'a1.txt', mode='w', encoding='utf-8') # 默认是wtf.writable()# writelines指的是可以放一个列表或者元组,里面可以有多行内容,需要自己加换行符f.writelines(['111111\n', '222222\n', '333333\n'])# 下面这样代码与上面写的结果一样# f.write('aaaaaa\nbbbbbbb\ncccccc\n')f.close()复制代码
3. 操作文件“a”模式
“a”模式指的是只追加写,当文件不存在时,创建空文件;当文件存在时,光标直接移至文件末尾,所以,我们在记录日志的时候都会使用“a”模式,代码示例如下:
f = open('access.log', mode='a', encoding='utf-8')print(f.writable())print(f.readable())f.write('5555555555555\n')f.close()复制代码
四 二进制模式打开文件的操作
1. “b”模式基本介绍
“b”模式指的是文件打开的模式为“b”模式, 它与“t”模式类似,不能单独使用,必须以“rb”,“wb”或者“ab”模式来使用,“b”模式读写都是以bytes为单位进行的,所以可以理解为“b”模式就是二进制模式。对于普通文本来说是以字符的形式保存的,但是对于图片,视频或者音频等等这些文件则是以二进制形式保存的,所以“t”模式无法读取,代码及报错示例如下:
图片文件并不是以字符编码保存的,而是以JPG这个格式保存成了二进制形式,与字符编码没有关系,所以我们以文本模式处理文件是不可行的。应该以二进制模式打开文件,这时不需要指定字符编码,正确的打开方式请看如下代码示例:# b模式下一定不能指定encoding参数with open('01.jpg', 'rb', ) as f: data = f.read() print(data)复制代码
2. 操作文件的“rb”模式
需要说明的一点是,“b”模式也可以读取文本文件,字符的底层都是以二进制形式存储的,只不过你在使用“t”模式读取文本文件的时候open帮你把二进制转成了能够看懂的文本,这是“t”模式的便利之处,但是它有局限性,只能操作文本文件,而“b”模式具有统一性,任何文件底层存储原理都是二进制,这也就是意味着“b”模式可以操作任何文件,代码示例如下:
with open('01.jpg', 'rb', ) as f1, open('a.txt', 'rb') as f2: img = f1.read() text = f2.read() print(text.decode('utf-8')) # 把bytes转化成utf-8复制代码
3. 操作文件的“wb”模式
“wb”模式也是操作文件“w”模式的一种,当文件存在时,就会清空该文件,当文件不存在时,就会创建空文件,代码示例如下:
# wb模式写入with open('a.txt', 'wb') as f: msg = '你好,世界' f.write(msg.encode('utf-8')) # 指定写入文件的字符编码# rb模式读取with open('a.txt', 'rb') as f: data = f.read() print(data) print(type(data)) print(data.decode('utf-8')) # 指定读取文件的字符编码复制代码
4. 操作文件的“ab”模式
“ab”模式指的是以二进制形式追加写,与操作文件的“a”模式同理,代码示例如下:
with open('a.txt', 'ab') as f: msg = '\n世界:你也好,小鬼' f.write(msg.encode('utf-8')) # 指定写入文件的字符编码复制代码
补充: 在这这里讲一个小模块的部分用法,是sys模块,它的使用说明请看下面代码示例和截图:
import sys # 首先导入这个模块list_test = sys.argv # 它的返回值是一个列表print(list_test)复制代码
接下来我们在终端环境下执行以下命令(注意参数1前后的空格):
你可以看到在终端执行打印的结果就是一个列表,第一个值是文件路径,第二个和第三个值分别是两个参数。5. 操作文件的其他模式(了解)
一般来说,你遇到的操作文件的模式都是只读或者只写,但是也有可读可写的模式,这类模式了解即可,说明和代码示例如下:
# "r+t"模式,或者写成"r+"模式,指的是可读可写with open('a.txt', 'r+t', encoding='utf-8') as f: print(f.readable()) print(f.writable())# "w+r"或者"w+"模式,可读可写with open('a.txt', 'w+t', encoding='utf-8') as f: print(f.readable()) print(f.writable())# "a+t"或者"a+",可读可追加写with open('a.txt', 'a+t', encoding='utf-8') as f: print(f.readable()) print(f.writable())# "U"模式,通用换行符,已废弃,无需了解# with open('a.txt', 'U', encoding='utf-8') as f:# print(f.readable())# print(f.writable())复制代码
“r+”与“w+”,“a+”模式都是可读可写,他们的区别在于不改变自身原本操作文件的形式,即“r+”模式下,当文件不存在会保存,“w+”或者“a+”模式当文件不存在会创建新文件,当文件存在会清空文件。
五 文件内光标移动
在打开文件时会有一个光标移动,我们使用seek这个方法,可以实现光标的移动,代码示例如下:
with open('a.txt', 'r') as f: f.seek(9) # 这个参数指的是偏移量,以字节为单位 data = f.read() print(data)复制代码
注意:光标移动只能是从左往右移动,seek可以加两个参数,第一个参数就是上面代码中的参数,你如果只传一个参数也就是指的这个参数,第二个参数默认是0,指的是光标在文件开头位置开始移动,除了0之外,只能接收1或者2作为参数,1表示从当前位置开始移动,2表示从文件末尾开始移动,其中1和2必须在“b”模式下进行,0可以在“t”模式或者“b”下都能运行,但是无论哪种模式,都是以bytes为单位进行的,代码示例如下:
with open('a.txt', 'rb') as f: f.seek(3, 0) # 移动三个字节,也就是utf-8编码下一个中文字符 print(f.tell()) # 当前光标位置,以字节为单位 f.seek(3, 1) # 从当前位置向右偏移3个字节然后再读取文件内容 # f.seek(3, 2) # 只能读取动态数据新添加的内容 data = f.read() print(data.decode('utf-8'))with open('a.txt', 'r') as f: f.seek(3, 0) print(f.read())复制代码
补充: 在这里补充一个小模块的用法,是os模块,它的使用说明请看下面代码示例:
import os # 首先导入这个模块os.rename('a.txt', 'b.txt') # 修改文件名,两个参数分别为源文件名和目标文件名os.remove('a1.txt') # 删除a1.txt文件,这个参数指的是文件路径复制代码