文件处理

一 文件操作

注操作文件的流程:

#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'

 

posted @ 2018-03-22 12:14  你的泪我的眼  阅读(155)  评论(0编辑  收藏  举报