文件操作基本介绍
python open()函数用于打开一个文件,创建一个file对象,相关的方法才可以调用它进行读写。
- 控制文件读写内容的模式:t和b (t和b不能单独使用,必须跟r/w/a连用)
- t 文本 (默认的模式)
- 读写都以str(unicode)为单位的
- 文本文件
- 必须指定encoding=’utf-8’ 一种编码格式进行编码
- b 二进制/bytes binary模式
- 读写都是以bytes为单位
- 可以针对所有文件
- 一定不能指定字符编码encoding参数
- t 文本 (默认的模式)
- 控制文件读写操作的模式
- r 只读模式
- w 只写模式
- 只追加写模式
- +:r+、w+、a+
模式 | r | r+ | w | w+ | a | a+ |
---|---|---|---|---|---|---|
读 | + | + | + | + | ||
写 | + | + | + | + | + | |
创建 | + | + | + | + | ||
清除数据 | + | + | ||||
指针在开始 | + | + | + | + | ||
指针在结尾 | + | + |
总结:
- 在操作纯文本文件方面t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码
- 针对非文本文件(图片、视频、音频等)只能使用b模式
文件操作的流程
- 打开文件
- 操作文件 读/写
- 关闭文件
f = open('test.txt')
res = f.read()
print(res)
f.close()
只指定了文件,其他均按参数的默认值。即mode=’rt’
read()是指读取文本的全部内容
关闭文件,回收资源
with上下文管理
with open()不仅可以处理单个文件,还可以同时处理多个文件,并且在程序执行完成后,自动关闭open的文件
with open('test.txt',mode='rt') as f:
res = f.read()
print(res)
with open('test.txt',mode='rt') as f1,open('test.ini',mode='rt') as f2:
res1 = f1.read()
res2 = f2.read()
print(res1)
print(res2)
指定字符编码
with open('test.txt',mode='rt') as f:
res = f.read() # t模式,会将f.read()读出的内容解码成unicode
print(res)
a. test.txt存在硬盘是utf-8格式的二进制
b. read() 执行时,是将test.txt的内容以utf-8格式二进制读入内存。上面的介绍中提到t模式无论读写都是以str(unicode)进行的。所以read()同时将utf-8格式的二进制解码为unicode
c. 这里open()没有指定encoding参数,操作系统会使用系统默认的编码
linux系统和mac系统,系统默认的编码是utf-8
windows系统,系统默认的编码是gbk
with open('test.txt',mode='rt',encoding='utf-8') as f1:
res1 = f1.read()
print(res1)
执行结果:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
另,可以通过chardet.detect()
函数查看当前操作文件的编码格式
chardet.detect(res)
文件操作模式
r模式
r是默认的操作模式,只读模式。当操作的文件不存在时,会报错。当文件存在是文件指针跳到开始位置。
with open('test.txt',mode='rt',encoding='utf-8') as f1:
print('第一次读'.center(50,'*'))
res1 = f1.read()
print(res1)
print('第二次读'.center(50, '*'))
res2 = f1.read()
print(res2)
执行结果:
***********************第一次读***********************
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”
***********************第二次读***********************
上面的代码第二次读取的内容为空,因为第一次读完,文件指针已经移到到文件内容的末尾,第二次读取时是从文件的末尾开始读取的,即为空
实例:
在user.txt中保存账号密码:laobai|123
通过程序读取user.txt中的账号信息,与用户输入的账号密码进行比对,验证账号信息是否正确。
input_username = input('请输入账号名称:').strip()
input_password = input('请输入密码:').strip()
with open('user.txt',mode='rt',encoding='utf-8') as f:
res = f.read()
username,password = res.split('|')
if input_username == username and input_password == password:
print('登录成功')
else:
print('账号或密码错误!')
执行结果:
请输入账号名称:laobai
请输入密码:123
登录成功
在user.txt存放多个账号时的处理方法
laobai|123
plscript|321
nichengwe|123456
input_username = input('请输入账号名称:').strip()
input_password = input('请输入密码:').strip()
with open('user.txt',mode='rt',encoding='utf-8') as f:
for line in f:
username,password = line.strip().split('|')
if input_username == username and input_password == password:
print('登录成功')
break
else:
print('账号或密码错误!')
执行结果:
请输入账号名称:nichengwe
请输入密码:123456
登录成功
w模式
w是只写模式,当文件不存在时,会创建空文件;当文件存在是会清空文件。文件指针位于开始位置。
test.txt的内容如下:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”
with open('test.txt',mode='wt',encoding='utf-8') as f:
f.write("laobai")
执行上面的代码,再次查看test.txt的内容
laobai
注意:
- 在以w模式打开文件没有关闭的情况下,连续写入,新的内容总是跟在旧的内容之后;
- 如果重新以w模式打开文件,则会清空文件内容;
实例:
test1.txt的内容如下:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
不知道昏迷了多久,朦朦胧胧中,一只手舀给他清凉的泉水。那是个年轻的僧侣,风尘仆仆,似乎远道而来。僧侣向他问路,他绝望的回答:“那个地方已经变成地狱,为什么还要前往。”
僧侣平静的问:“你似乎被心魔所困扰。”
达摩说:“是啊,因为这不幸的结果是我亲手造成的。”他大笑着,自己生来的使命本该是降服邪恶,最终自己反倒变成邪恶。
僧侣却摇了摇头:“你并非邪恶,只是太过懦弱。毁灭容易,建造太难。你一直徘徊在这里:不敢回头,因为不相信自己造就了黑暗;没有勇气离去,因为不敢跨出这片黑暗。”
达摩反问他:“那你呢?明知已降下黑暗,还为何来到这里。”
僧侣“阿弥陀佛”了一声:“贫僧自东方而来,要前往西天取经之地。长安,很快也将黑夜降临。贫僧跋涉千山万水,或许可以找到重建的方法,带回一丝光明。”
达摩握紧了拳头。
他不相信自己生来为魔。
他本应肩挑凡世,拳握初心。
他在黑夜中迷惘,忘记了走不通的路,应该用拳头来打开。
他的本性如此,并不重要。然而见性,方能成佛。
人生是场穷游,偶尔也需要暴走。
道路很远,脚步更长。
告别僧侣,他毅然迈向相反的方向。已回不去故土,就只能继续前进。他要去看看僧侣出发地方——长安,内心的声音告诉他,那里有他寻找的东西。
最深的黑夜,往往是光明所在。
“肩挑凡世,拳握初心。”
test2.txt为空文件
实现test1.txt文件的内容复制到test2.txt中
with open('test1.txt',mode='rt',encoding='utf-8') as f1,\
open('test2.txt',mode='wt',encoding='utf-8') as f2:
res = f1.read()
f2.write(res)
执行完毕后,test1.txt中的内容被拷贝到test2.txt中。再次执行,内容只有一份,与test1.txt的内容一致。
a模式
a模式是只追加写模式,在文件不存在时会创建空文档,在文件存在时文件指针会直接跳到末尾。
test.txt的内容如下:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”
with open('test.txt',mode='at',encoding='utf-8') as f:
f.write("laobai")
执行上面的代码,再次查看test.txt的内容
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”laobai
注意:w模式与a模式的异同
- 相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟着之前写的内容之后;
- 不同点:以a模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写入的内容永远在文件末尾
实例:
在user.txt文件中保存账号密码,文件内容如下:
laobai|123
sch|321
nichengwe|123456
通过程序输入新的账号密码存入user.txt中
input_name = input("请输入注册名:").strip()
input_password = input("请输入密码:").strip()
with open('user.txt',mode='at',encoding='utf-8') as f:
f.write('{}|{}\n'.format(input_name,input_password))
执行程序后,再次查看user.txt的内容
laobai|123
plscript|321
nichengwe|123456
laobai1|123
+t模式
+不能单独使用,必须配合r、w、a进行使用。而除了均有了读写功能外,其他特性与r、w、a保持一致。
注意:read()和write()都是从光标的位置开始读或写。
a. r+
例子1:
test.txt内容如下:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”
通过r+模式向test.txt读取并写入内容
with open('test.txt',mode='r+',encoding='utf-8') as f:
print(f.read())
f.write('nichengwe')
print(f.read())
执行程序
test.txt新内容如下:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”nichengwe
程序运行结果如下:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”
分析程序运行结果:
- f.read() 读取test.txt中的全部内容,并将文件指针指向文件内容的末尾
- write(‘nichengwe’) 在文件末尾写入nichengwe,并将文件指针指向文件内容的末尾
- 再次执行f.read() 从文件末尾开始读取,读取到的是空
例子2:
test.txt内容如下:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”nichengwe
通过r+模式向test.txt写入内容
with open('test.txt',mode='r+',encoding='utf-8') as f:
f.write('nichengwe')
r模式打开文件,文件指针在文件内容的开头
write()是在文件开头开始写入内容
执行程序后,test.txt的内容如下:
nichengwe为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”nichengwe
test.txt文件内容的前几个字被新写入的内容覆盖了
b. w+
例子1:
test.txt的内容如下:
nichengwe为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
“肩挑凡世,拳握初心。”nichengwe
通过w+模式读取文件内容:
with open('test.txt',mode='w+',encoding='utf-8') as f:
print(f.read())
w模式打开文件,首先清空文件所有内容,文件指针在文件内容的开头
程序执行后,没有读取到任何内容,因为w模式已经将文件的所有内容清空了。
例子2:
test.txt的内容为空白
通过w+模式写入并读取文件内容:
with open('test.txt',mode='w+',encoding='utf-8') as f:
f.write('nichengwe')
f.write('laobai')
f.write('baby2016的天空')
print("------->",f.read())
执行结果为:
------->
执行程序后,test.txt的内容为:
nichengwelaobaibaby2016的天空
分析程序运行结果:
- w模式打开文件,会清空文件的所有内容,并将文件指针指向文件的开头
- write() 从文件指针的位置写入内容,写入了3次,文件指针指向文件的末尾
- read() 从文件指针的位置开始读取,读取的内容为空
c. a+
例子:
test.txt的内容如下:
nichengwelaobaibaby2016的天空
通过a+模式读写文件:
with open('test.txt',mode='a+',encoding='utf-8') as f:
print("=======》", f.read())
f.write('\nnichengwe\n')
f.write('laobai\n')
f.write('baby2016的天空\n')
print("------->",f.read())
执行结果:
=======》
------->
执行程序后test.txt的内容如下:
nichengwelaobaibaby2016的天空
nichengwe
laobai
baby2016的天空
分析程序运行结果:
- a模式打开文件,文件指针会在文件的末尾
- read() 从文件指针的位置开始读取,内容为空,文件指针依旧在文件末尾
- write() 从文件指针的位置开始写入内容,多次写入后,文件指针依旧在文件末尾
- 再次read() 从文件指针的位置开始读取,内容为空,文件指针依旧在文件末尾
b模式
处理图片:
with open('test.jpg',mode='rb') as f:
res = f.read() # 硬盘的二进制读入内容 ——> b模式下,不做任何转换
print(res) # bytes类型——> 当成二进制
print(type(res))
执行结果:
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x90\x00\x90\x00\x00\xff\xe1\x00tExif\x00\x00MM\x00*\x00\x00\x00\x08\x00\x04\x01\x1a\x00\x05\x00\x00\x00\x01\x00\x00\x00>\x01\x1b\x00\x05\x00\x00\x00\x01\x00\x00\x00F\x01(\x00\x03\x00\x00\x00\x01\x00\x02\x00\x00\x87i\x00\x04\x00\x00\x00\x01\x00\x00\x00N\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x01\x00\x00\x00\x90\x00\x00\x00\x01\x00\x02\xa0\x02\x00\x04\x00\x00\x00\x01\x00\x00\x02\x92\xa0\x03\x00\x04\x00\x00\x00\x01\x00\x00\x01
<class 'bytes'>
处理文本:
with open('user.txt',mode='wb') as f:
f.write('你好hello'.encode('gbk'))
由于本机使用的是macos,默认编码为utf-8,而这里程序使用了gbk,所以写入的你好会显示为乱码。
例子:
# 文件拷贝工具
file1 = input('源文件路径:').strip()
file2 = input('目标文件路径:').strip()
with open(r'{}'.format(file1),mode='rb') as f1,\
open(r'{}'.format(file2),mode='wb') as f2:
#res = f1.read() # 这种方式内存占用过大
for line in f1:
f2.write(line)
readline()和readlines()
readline()
按行读取,每次读一行
例子1:
with open('test1.txt',mode='rt',encoding='utf-8') as f:
res1 = f.readline()
res2 = f.readline()
print(res1)
print(res2)
执行结果:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
例子2:
with open('test1.txt',mode='rt',encoding='utf-8') as f:
while True:
line = f.readline()
if len(line) == 0:
break
print(line)
执行结果:
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
告别僧侣,他毅然迈向相反的方向。已回不去故土,就只能继续前进。他要去看看僧侣出发地方——长安,内心的声音告诉他,那里有他寻找的东西。
最深的黑夜,往往是光明所在。
“肩挑凡世,拳握初心。”
readlines()
按行读取,将所有行都读取出来,每一个作为一个元素,组成一个大列表。
例子1:
with open('test1.txt',mode='rt',encoding='utf-8') as f:
res = f.readlines()
print(res)
执行结果:
['达摩是为降伏邪恶而生的。曾经有人这样预言。\n', '他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。\n', '但国破家亡就在转瞬之间。父王被叛徒毒死,黑色风暴席卷了大地。人们哀嚎着被杀害。最后,他被逼入绝境。自己的拳头可以面对最强大的敌人,却无法对同胞出手。尽管血脉相连的亲人们在权力的诱惑下陷入疯魔,变得面目可憎。\n', '道路很远,脚步更长。\n', '告别僧侣,他毅然迈向相反的方向。已回不去故土,就只能继续前进。他要去看看僧侣出发地方——长安,内心的声音告诉他,那里有他寻找的东西。\n', '最深的黑夜,往往是光明所在。\n', '“肩挑凡世,拳握初心。”']
f.read()和f.readlines()都是将内容一次性读入内存,如果内容过大会导致内存溢出。
例子2:
可以将列表里的内容,通过writelines()形式按行写入
l = ['达摩是为降伏邪恶而生的。曾经有人这样预言。\n', '他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。\n', '但国破家亡就在转瞬之间。父王被叛徒毒死,黑色风暴席卷了大地。人们哀嚎着被杀害。最后,他被逼入绝境。自己的拳头可以面对最强大的敌人,却无法对同胞出手。尽管血脉相连的亲人们在权力的诱惑下陷入疯魔,变得面目可憎。\n', '道路很远,脚步更长。\n', '告别僧侣,他毅然迈向相反的方向。已回不去故土,就只能继续前进。他要去看看僧侣出发地方——长安,内心的声音告诉他,那里有他寻找的东西。\n', '最深的黑夜,往往是光明所在。\n', '“肩挑凡世,拳握初心。”']
with open('test.txt',mode='wt',encoding='utf-8') as f:
f.writelines(l)
执行后,test.txt的内容为
达摩是为降伏邪恶而生的。曾经有人这样预言。
他是王者之子,生在一棵优美的菩提树下,从小由德高望重的大师教导经书和拳法,那时他日日刻苦修行,救助身边不幸的人们,并对自己的使命坚信不疑。
但国破家亡就在转瞬之间。父王被叛徒毒死,黑色风暴席卷了大地。人们哀嚎着被杀害。最后,他被逼入绝境。自己的拳头可以面对最强大的敌人,却无法对同胞出手。尽管血脉相连的亲人们在权力的诱惑下陷入疯魔,变得面目可憎。
道路很远,脚步更长。
告别僧侣,他毅然迈向相反的方向。已回不去故土,就只能继续前进。他要去看看僧侣出发地方——长安,内心的声音告诉他,那里有他寻找的东西。
最深的黑夜,往往是光明所在。
“肩挑凡世,拳握初心。”
文件指针移动
指针移动的单位都是以bytes/字节为单位
只有一种情况特殊:t模式下的read(n),n代表的是字符个数
with open('test.txt',mode='rt',encoding='utf-8') as f:
res = f.read(4)
print(res)
seek()
f.seek(n,模式):
- n指的是移动的字节个数
- 模式参照物文件指针的位置
- 0:参照物是文件开头位置
- 1:参照物是当前指针所在位置
- 2:参照物是文件末尾位置(这个模式是反向向前移动)
只有模式0可以在t模式下使用,1和2必须在b模式下用
f.teel() 获取当前文件指针的位置
例子:0模式
with open('test.txt',mode='rb') as f:
f.seek(9,0)
f.seek(3,0)
print(f.tell())
执行结果:
3
例子:1模式
with open('test.txt',mode='rb') as f:
f.seek(9,1)
f.seek(3,1)
print(f.tell())
执行结果:
12
例子:2模式
with open('test.txt',mode='rb') as f:
f.seek(-9,2)
print(f.tell())
f.seek(-3,2)
print(f.tell())
执行结果:
882
888