文件处理
一 文件操作
注操作文件的流程:
#1. 打开文件,得到文件句柄并赋值给一个变量 #2. 通过句柄对文件进行操作 #3. 关闭文件
f=open('a.txt','r')的过程分析
#1、由应用程序向操作系统发起系统调用open(...) #2、操作系统打开该文件,并返回一个文件句柄给应用程序 #3、应用程序将文件句柄赋值给变量f
强调!!!
#强调第一点: 打开一个文件包含两部分资源:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为: 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')
python2中的file与open
#首先在python3中操作文件只有一种选择,那就是open() #而在python2中则有两种方式:file()与open() 两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用file()来打开文件,相当于这是在构造文件类,而用open()打开文件,是用python的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如type(f) is file
二 打开文件的模式
文件句柄 = open('文件路径', '模式') #1. 打开文件的模式有(默认为文本模式): r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】 w,只写模式【不可读;不存在则创建;存在则清空内容】 a, 之追加写模式【不可读;不存在则创建;存在则只追加内容】 #2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式) rb wb ab 注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码 #3. 了解部分 "+" 表示可以同时读写某个文件 r+, 读写【可读,可写】 w+,写读【可读,可写】 a+, 写读【可读,可写】 x, 只写模式【不可读;不存在则创建,存在则报错】 x+ ,写读【可读,可写】 xb
三 操作文件方法
#掌握 f.read() #读取所有内容,光标移动到文件末尾 f.readline() #读取一行内容,光标移动到第二行首部 f.readlines() #读取每一行内容,存放于列表中 f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符 f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符 f.writelines(['333\n','444\n']) #文件模式 f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式 #了解 f.readable() #文件是否可读 f.writable() #文件是否可读 f.closed #文件是否关闭 f.encoding #如果文件打开模式为b,则没有该属性 f.flush() #立刻将文件内容从内存刷到硬盘 f.name
四 文件内光标移动
一: read(3): 1. 文件打开方式为文本模式时,代表读取3个字符 2. 文件打开方式为b模式时,代表读取3个字节 二: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate 注意: 1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的 2. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果
刚打开文件就调用它会清空文件。
file.seek()方法标准格式是:seek(offset,whence=0) offset:开始的偏移量,也就是代表需要移动偏移的字节数 whence:给offset参数一个定义,表示要从哪个位置开始偏移; 0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。默认为0 一个相关的例子: 用yield生成器模拟Linux中命令:tail -f file | grep python 用于查找监控日志文件中出现有python字样的行 # 注意程序只检测新增的日志信息! #当程序运行时,若warn.log文件中末尾有新增一行,且该一行包含python,该行就会被打印出来 #若打开warn.log时,末尾已经有了一行包含python,该行不会被打印,因为上面是f.seek(0,2)移动到了文件EOF处 #故,上面程序实现了tail -f warn.log | grep 'python'的功能,动态实时检测warn.log中是否新增现了 #新的行,且该行包含python def tail(f): # 移动到文件的EOF最后 f.seek(0.2) while 1: # 读取文件中新的文本行 line = f.readline() if not line:continue # yield 出每一行的数据 yield line def grep(lines,search_text): for line in lines: if search_text in line: yield line if __name__ == '__main__': flog = tail(open('log.log')) py_lines = grep(flog,'python') for line in py_lines: print(line)
五 文件的修改
文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(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')
六 自己的一些收集
linux上处理windows上的文件时最好用 rb wb,还有进行文件传输的时候也要用b(二进制),避免 编码方式的不同导致错误,而且文件中不止文本有图片等的情况会出错.b模式跨平台,因为所有系统存储数据都是二进制.
1.python 2.x中: 默认都是读取文本文件,并且是ASCII编码的文本文件。要读取二进制文件,比如图片、视频等等, 用'rb'模式打开文件即可: >>> f = open('/Users/michael/test.jpg', 'rb') >>> f.read() '\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六进制表示的字节 字符编码:读取非ASCII编码的文本文件,就必须以二进制模式打开,再解码。比如GBK编码的文件: >>> f = open('/Users/michael/gbk.txt', 'rb') >>> u = f.read().decode('gbk') #将二进制解码,存文件encode,读取文件decode >>> u u'\u6d4b\u8bd5' >>> print u 测试
6.1文件读写注意:文件写入的是字符串,不能这样
a = [1,2,3]
f.write(a)
不能f.write(5)
f = open(‘1.txt’,’w’,’buffersize’),其实跟file是一样的,是file的别名。 文件打开的过程中不能更改模式,除非r+或者w+模式。
with open('1.txt','w','buffersize') as f: f.write('aaa') #w模式不会自动换行,需要加上 \n,a 模式会自动加上\n f.writelines(['12\n','34\n']) f.close() #关闭文件,with模式下不用,会自动关闭。 f.seek(-1,2), 从文件末尾为原点计算,读取倒数第一个字符 f.read() f.readline() f.readlines() 读取整个文件为列表,将文件全部读取到内存 f.xreadlines() 一行一行读取到内存中,处理大文件必须要用它,不要用readlines。 f.write() f.writeline() f.truncate() #截取文件,默认截取到当前位置。刚打开文件就调用它会清空文件。 f.flush() #将文件内存中的内容写到磁盘 注意:linux上处理windows上的文件时最好用 rb wb,还有进行文件传输的时候也要用b(二进制),避免编码方式的不同导致错误。 f = file('1.txt','w') #帮助 help(file),跟open是一样的 操作方法同上 f = file('test.txt','r') 遍历文件 for line in f.xreadlines(): #大文件必须用xreadlines()一行一行读 print line, #加上, 不打印换行符
6.2文件内容更改
fileinput模块提供处理一个或多个文本文件的功能,可以通过使用for循环来读取一个或多个文本文件的所有行。 【默认格式】 fileinput.input (files='filename', inplace=False, backup='', bufsize=0, mode='r', openhook=None) files: #文件的路径列表,默认是stdin方式,多文件['1.txt','2.txt',...] inplace: #是否将标准输出的结果写回文件,默认不取代 backup: #备份文件的扩展名,只指定扩展名,如.bak。如果该文件的备份文件已存在,则会自动覆盖。 bufsize: #缓冲区大小,默认为0,如果文件很大,可以修改此参数,一般默认即可 mode: #读写模式,默认为只读 openhook: #该钩子用于控制打开的所有文件,比如说编码方式等; 【常用函数】 1 fileinput.input() #返回能够用于for循环遍历的对象 2 fileinput.filename() #返回当前文件的名称 3 fileinput.lineno() #返回当前已经读取的行的数量(或者序号) 4 fileinput.filelineno() #返回当前读取的行的行号 5 fileinput.isfirstline() #检查当前行是否是文件的第一行 6 fileinput.isstdin() #判断最后一行是否从stdin中读取 7 fileinput.close() #关闭队列 实例:替换Rain为Jerry for line in fileinput.input('user.txt',backup='.bak',inplace=1): line = line.replace('Rain','Jerry') print line,
实例:向文件中指定位置插入内容
def file_insert(fname, str): r = ur'}' f = open(fname) old = f.read() num = int(re.search(r, old).start()) #正则找到要插入到的位置。 f_input = fileinput.input(fname, inplace=1) #for line in fileinput.input(fname, inplace=1): for line in f_input: if r in line: print line.rstrip() #让stdout被重定向到输入文件里 print "\n"+str+"\n" #让stdout被重定向到输入文件里,str是要插入的内容 f.seek(num+2) #移动到插入位置末尾。 print f.read() #让stdout被重定向到输入文件里,将剩余的内容打印 break else: print line.rstrip() f.close() f_input.close() #print "OK! The %s configure has been sucessfull added!" % fname print "Ok! 配置文件%s已经添加成功!" % fname 注意: fileinput.input的inplace必须要设为1,以便让stdout被重定向到输入文件里。
6.3大文件迭代方法:
1.while + readline f = open('text.txt',r) while true: line = f.readline() 一行一行读取,每读取一行文件指针移动到下一行 if line: pass else: break 2.xrandlines() 3.文本文件自带的迭代: f = open('text.txt',r) for i in f: pass 4.用yield生成器。
6.4核心笔记:保留分行符
当使用输入方法如read()或者readlines()从文件度取行时,python不会删除结束符。文件写操作一样不会写入 结束符号(n).
行分隔符和其它文件系统的差异:不同操作系统所支持的行分隔符,路径分隔符,都不同。为了有助于跨平台开发, os模块的以下属性,在不同平台会自动设置成相应的值。
>>> import os >>> os.linesep '\n' >>> os.pathsep ':' >>> os.sep '/' >>> os.curdir '.' >>> os.pardir '..' >>>
6.5标准文件: sys.stdin sys.stdout sys.stderr
标准输入:一般是键盘。stdin对象为解释器提供输入字符流,一般使用raw_input()和input()函数。 name = sys.stdin.readline() 相当于 raw_input()
标准输出:一般是屏幕。stdout对象接收到print语句产生的输出。 sys.stdout.write()方法其实就是上面所讲的标准输出,print语句就是调用了这个方法
错误输出:一般是错误信息。stderr对象接收出错的信息。
实例:从控制台重定向到文件。
记住,如果你还想在控制台打印一些东西的话,最好先将原始的控制台对象引用保存下来, 向文件中打印之后再恢复 sys.stdout:
_console__ = sys.stdout #保存原始控制台 import sys f_handler=open('out.log', 'w') sys.stdout=f_handler #标准输出重定向到文件 print 'hello' print 'hello' print 'hello' f_handler.close() sys.stdout= __console__ #恢复控制台 print 'console'