一、文件操作
1、介绍
计算机系统分为:计算机硬件,操作系统,应用程序三部分。
我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众所周知,应用程序是无法直接操作硬件的,这就用到了操作系统。操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。
有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:
#1. 打开文件,得到文件句柄并赋值给一个变量 #2. 通过句柄对文件进行操作 #3. 关闭文件
2、在python中
#1. 打开文件,得到文件句柄并赋值给一个变量 f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r #2. 通过句柄对文件进行操作 data=f.read() #3. 关闭文件 f.close()
3、f=open('a.txt','r')的过程分析
#1、由应用程序向操作系统发起系统调用open(...) #2、操作系统打开该文件,并返回一个文件句柄给应用程序 #3、应用程序将文件句柄赋值给变量f
4、强调
第一点:
打开一个文件包含两部分资源:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为: 1、f.close() #回收操作系统级打开的文件 2、del f #回收应用程序级的变量 其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源, 而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close() 虽然我这么说,但是很多同学还是会很不要脸地忘记f.close(),对于这些不长脑子的同学,我们推荐傻瓜式操作方式:使用with关键字来帮我们管理上下文 with open('a.txt','w') as f: pass with open('a.txt','r') as read_f,open('b.txt','w') as write_f: data=read_f.read() write_f.write(data)
第二点:
f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,
在linux下是utf-8。
这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。 f=open('a.txt','r',encoding='utf-8')
5、python2中的file与open
#首先在python3中操作文件只有一种选择,那就是open() #而在python2中则有两种方式:file()与open() 两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用file()来打开文件,相当于这是在构造文件类,而用open()打开文件,
是用python的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如type(f) is file
6、实操:
f=open('a.txt',mode='r',encoding='utf-8') #读/写 data=f.read() # print(data) #关闭 # del f #回收python资源 # f.close() #回收操作系统的资源 # del f # print(f) #流程分析: #1:向操作系统发起系统调用 #2:操作系统打开这个文件,返回一个文件句柄给应用程序 #3: 在应用程序中把文件句柄赋值给一个变量 #注意两点: #1:打开一个文件对应两部分,一个Python级别的文件句柄,另外一个是操作系统打开的文件(默认 #打开文件的编码是以操作系统的编码为准的,除非open()指定encoding='编码' ) #2:当文件操作完毕后,应该回收两部分资源, #del f:回收应用程序资源(python解释器自动的垃圾回收机制已经替我们做了) #f.close:回收操作系统 #上下文管理with with open('a.txt',mode='r',encoding='utf-8') as f: print(f.read())
二、打开的文件模式
1、实操
#r:默认的打开模式,只读,文件不存在则报错 # f=open('a.txt',encoding='utf-8') # print('===>',f.read()) #读所有,bytes---decode('utf-8')--->str # print('===>',f.read()) # print(f.readlines()) #读所有,结果放入列表中 # print(f.readline(),end='') #一次读一行 # print(f.readline(),end='') # print(f.readline(),end='') # print(f.readline(),end='') # f.close() #w:只写模式,如果文件存在则清空,如果文件不存在则新建 # f=open('b.txt',mode='w',encoding='utf-8') # f.write('11111 ') #unicode---encode-->bytes # f.write('2222 ') # f.write('333333 ') # l=['444 ','55555 ','66666 '] # for line in l: # f.write(line) # f.writelines(['444 ','55555 ','66666 ']) # f.close() #a:追加写模式,如果文件存在则把光标移动到文件末尾,如果文件不存在则新建 # f=open('c.txt','a',encoding='utf-8') # f.write('333333 ') # f.write('444444 ') # f.writelines(['5555 ','666 ']) # # f.close() #遍历文件 # with open('a.txt',encoding='utf-8') as f: # #不推荐使用 # # lines=f.readlines() # # for line in lines: # # print(line,end='') # #推荐使用 # for line in f: # print(line,end='') #b:以bytes的形式去操作文件内容,不能指定编码 # with open('yuanhao.jpg',mode='rb') as f: # print(f.read().decode('utf-8')) # # with open('a.txt',mode='rb') as f: # data=f.read() # print(data.decode('utf-8')) # with open('d.txt',mode='wb') as f: # f.write('哈哈哈hello'.encode('utf-8')) with open('d.txt', mode='ab') as f: f.write('哈哈哈hello'.encode('utf-8')) #了解部分 # print(f.readable()) # print(f.writable())
补充:
with open('a.txt',encoding='utf-8') as f: # lines=f.readlines() # for line in lines: # # print(line) # print(line,end='') # while True: # line=f.readlines() # if len(line) == 0: # break # print(line,end='') for line in f: print(line,end='') #推荐for循环!
三、布尔值
#bool值:所有的数据类型都自带布尔值 #布尔值为假的情况:0,空,None x=None # print(bool(x)) if x: print('ok') else: print('ono')
四、操作文件的方法
#掌握 f.read() #读取所有内容,光标移动到文件末尾 f.readline() #读取一行内容,光标移动到第二行首部 f.readlines() #读取每一行内容,存放于列表中 f.write('1111 222 ') #针对文本模式的写,需要自己写换行符 f.write('1111 222 '.encode('utf-8')) #针对b模式的写,需要自己写换行符 f.writelines(['333 ','444 ']) #文件模式 f.writelines([bytes('333 ',encoding='utf-8'),'444 '.encode('utf-8')]) #b模式 #了解 f.readable() #文件是否可读 f.writable() #文件是否可读 f.closed #文件是否关闭 f.encoding #如果文件打开模式为b,则没有该属性 f.flush() #立刻将文件内容从内存刷到硬盘 f.name
五、文件内光标移动
5.1: read(3):
1. 文件打开方式为文本模式时,代表读取3个字符
2. 文件打开方式为b模式时,代表读取3个字节
5.2 : 其余的文件内光标移动都是以字节为单位如seek,tell,truncate
注意:
1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的
2. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果
import time with open('test.txt','rb') as f: f.seek(0,2) while True: line=f.readline() if line: print(line.decode('utf-8')) else: time.sleep(0.2)
六、文件的修改
文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)
import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: data=read_f.read() #全部读入内存,如果文件很大,会很卡 data=data.replace('alex','SB') #在内存中完成修改 write_f.write(data) #一次性写入新文件 os.remove('a.txt') os.rename('.a.txt.swap','a.txt')
方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件
import os with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f: for line in read_f: line=line.replace('alex','SB') write_f.write(line) os.remove('a.txt') os.rename('.a.txt.swap','a.txt')