python文件操作(一)
一 文件操作介绍
计算机系统分为:硬件系统、软件系统两部分,软件系统又可以分为系统软件和应用软件。
我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,但是,应用程序是无法直接操作硬件的,需要通过操作系统来完成。操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。
这样的话,我们只需要关注操作文件的流程就行了,也就是:
1.打开文件,得到文件句柄并赋值给一个变量
2.通过句柄对文件进行操作
3.关闭文件
二 python实现流程
根据上面的流程,在python中我们是这样实现的:
#1. 打开文件,得到文件句柄并赋值给一个变量 f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r,也就是读文件 #2. 通过句柄对文件进行操作 data=f.read() #3. 关闭文件 f.close()
现在我们可以分析一下第一步,操作系统和应用程序是怎么交互的:
1.由应用程序向操作系统发起系统调用open()
2.操作系统打开该文件,并返回一个文件句柄给应用程序
3.应用程序将文件句柄赋值给变量f
注意事项:
1.千万记得操作完文件后要写f.close()。从上面的交互流程我们可以看到,打开一个文件是包含两部分资源的:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为:
1、f.close() #回收操作系统级打开的文件 2、del f #回收应用程序级的变量
其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源,
而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close()
但还是经常有人会忘记加上,所以还有一种方式打开文件,并且不用你写close,就是通过with来管理上下文:
with open('a.txt','w') as f: data = f.read() with open('a.txt','r') as read_f,open('b.txt','w') as write_f: data=read_f.read() write_f.write(data) #第二种格式通过逗号分开,可以在一行打开两个文件
2.建议指定编码。有时候大家打开文件,发现拿到的数据都是乱码的,这是因为f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。若要保证不乱码,文件以什么方式存的,就要以什么方式打开。
f=open('a.txt','r',encoding='utf-8')
三 打开文件的模式
从上文我们知道:文件句柄 = open('文件路径', '模式'),模式可以是以下方式以及他们之间的组合:
|
|||||||||||||||||
我们逐个举例说明:
'r'模式,只读模式【默认模式,文件必须存在,不存在则抛出异常】,所以我们首先要有一个文件,我这里文件叫'陈粒',内容如下:
11111111 222222222 333 4444 555 555 6666 555 6666
'r'模式操作如下:
f=open('陈粒',encoding='utf-8') data=f.read() print(data) f.close()
这样我们拿到的是文件所有的内容,那我们要一行行的读,就要用到readline()方法:
f=open('陈粒','r',encoding='utf-8') print(f.readable()) print('第1行',f.readline()) print('第2行',f.readline()) print('第3行',f.readline())
结果是:
True
第1行
第2行
第3行
f=open('陈粒','r',encoding='utf-8') data=f.readlines() print(data) print(data[-1]) f.close()
结果是:
['11111111\n', '222222222\n', '333\n', '4444\n', '555\n', '555\n', '6666\n', '555\n', '6666\n'] 6666
可以看到readlines()拿到的是所有结果,但是按行放在一个列表里面,通过列表索引,我们可以拿到任何一行的内容。
'w'模式:只写模式【不可读;不存在则创建;存在则清空内容】,可以自己创建,那就简单了,直接来:
f=open('陈粒1','w',encoding='utf8') f.write('11111111\n') f.write('222222222\n') f.write('333\n4444\n555\n') f.close()
运行之后你会发现,多了一个文件叫“陈粒1”,里面就是我们写入的内容:
11111111 222222222 333 4444 555
可见我们可以写一行,加上换行符就可以写多行,那除了write()方法,还有别的方法可以写吗?当然是有的,比如writelines(),和我们的readlines()感觉对应,所以里面的内容也要是一个列表:
f=open('陈粒1','w',encoding='utf8') f.write('11111111\n') f.write('222222222\n') f.write('333\n4444\n555\n') f.writelines(['555\n','6666\n']) f.close()
再看我们的文件,又多了两行。下面再看一段代码:
f=open('陈粒1','w',encoding='utf8') f.write('11111111\n') f.write('222222222\n') f.write('333\n4444\n555\n') f.writelines(['555\n','6666\n']) f.writelines(['555\n','6666\n',1]) # 文件内容只能是字符串,只能写字符串 f.close()
运行之后发现报错了,因为我们最后写入了一个数字,而文件的内容都是字符串,所以写也都是写入字符串的,不能写数字,当然其他类型也是不可以的。
'a'追加写模式【不可读;不存在则创建;存在则只追加内容】,看到我们上面的w模式,写在同一个文件里面,会把之前的覆盖,那么如果只想在文件里面加点东西,显然需要另一种模式,就是a模式:
f=open('陈粒1','a',encoding='utf-8') f.write('写到文件最后')
这时候看结果,最后已经加上一行了:
11111111
222222222
333
4444
555
555
6666
555
6666
写到文件最后
上面说的3种模式非常简单,也是我们常用的3种模式,但都只是单一的模式,很多时候我们需要同时对一个文件进行读写操作,就需要这三个配合'+'一起使用了:
"+" 表示可以同时读写某个文件 r+, 读写【可读,可写】 w+,写读【可读,可写】 a+, 写读【可读,可写】
在说这三个模式之前,需要了解一个知识点就是:文件没有修改这一说,大家所认知的修改文件,是应用程序为了方便使用写的一个功能,改是在内存中改,但最终还是覆盖硬盘中的源文件,所以修改文件本质上是覆盖之前的文件。所以我们看看'r+'模式:
f = open('陈粒1','r+',encoding='utf-8') data = f.read() print(data) # f.write('aaa') f.close()
从结果看到,读文件是没有问题的,现在把写的那一行取消注释,看看文件内容:
11111111
222222222
333
4444
555
555
6666
555
6666
写到文件最后aaa
不会换行写,如果你要换行写,就要在aaa前面加上\n,那单独写是什么情况:
f = open('陈粒1','r+',encoding='utf-8') # data = f.read() # print(data) f.write('aaa') # f.write('\naaa') f.close()
结果是:
aaa11111 222222222 333 4444 555 555 6666 555 6666 写到文件最后
覆盖了前面三个111,因为光标默认是0,而写是从光标处开始写的,所以导致覆盖,这几种模式理解就行,用到不多。那如果我们要修改文件怎么办?就要打开两个文件了:
r_f = open('陈粒1','r',encoding='utf-8') data = r_f.readlines() r_f.close() w_f = open('陈粒2','w',encoding='utf-8') data.pop(2) w_f.writelines(data) w_f.close()
一个文件读,一个文件写,写之前把读到的数据列表删除了一个元素,所以’陈粒2‘文件就少了一行333,这样就实现了文件修改啦。有人说这样拿到的是新文件,但我想要在原来的文件修改怎么办?那就在改完之后把源文件删除后,再把新文件rename一下就好了,os模块能搞定这个需求。下一篇要讲的是二进制方式打开文件。