第六章 文件与文件操作

文件与文件操作

文本文件
二进制文件

一、 文件对象常用方法与属性

   无论是文本文件还是二进制文件,其操作流程基本都是一致的,即首先打开文件并创建文件对象,然后通过该文件对象对文件内容进行读取、写入、删除、修改等操作;最后关闭并保存文件内容。
   Python内置了文件对象,通过open()函数即可以指定模式打开指定文件并创建文件对象,该函数用法为


open(file,mode='r',buffering=-1,encoding=None,
errors=None,newline=None,closefd=True,opener=None)

该函数的主要参数含义如下。
(1)参数file指定要打开或创建的文件名称,如果该文件不在当前目录中,则需要指定完整路径,为了减少完整路径中“\”符号的输入,可以使用原始字符串。
(2)参数mode(取值范围见表6-1)指定打开文件后的处理方式,如“只读”、“只写”、“读写”、“追加”、“二进制只读”、“二进制只读”、“二进制读写”等,默认为“文本只读模式”。以不同方式打开文件时,文件指针的初始位置略有不同,例如,以“只读”和“只写”模式打开文件时文件指针的初始位置是文件头,而以“追加”模式打开文件时则文件指针的初始位置为文件尾。
(3)参数buffering指定读写文件的缓存模式,数值0(只在二进制模式中可以用)表示不缓存,数值1(只在文本模式中可以使用)表示使用缓存模式,大于1的数字则表示缓冲区的大小,默认值是-1。当使用默认值-1时,二进制文件和非交互式文本文件以固定大小的块为缓存单位,等价于io.DEFAULT_BUFFER_SIZE,交互式文本文件(isatty()方法返回True)采用行缓存模式。
(4)参数encoding指定对文本进行编码和解码的方式,只适用于文本模式,可以使用Python支持的任何格式,详见标准库codecs。
(5)参数newline只适用于文本模式,取值可以是None,"、’\n’、’\r’、’\r\n’中的任何一个,表示文件中新行的形式。
如果执行正常,open()函数返回一个可迭代的文件对象,通过该文件对象可以对文件进行读写操作,如果指定文件不存在,访问权限不够、磁盘空间不够或其他原因导致创建文件对象失败则抛出异常。
下面的代码分别以读、写方式打开了两个文件并创建了与之对应的文件对象。

f1=open('file1.txt','r')
f2=open('file2.txt','w')

当对文件内容操作完成以后,一定要关闭文件对象,这样才能保证所做的任何修改都确实被保存到文件中。
f.close()

 缓存机制使得修改文件时不需要频繁地进行磁盘文件地读写操作,
 而是等缓存满了以后再写入文件,或者调用flush()方法强行将
 缓存中的内容写入磁盘文件,缓冲机制大幅度提高了文件操作
 速度,也延长了磁盘使用寿命。
模式说明
r读模式(默认模式,可省略),如果文件不存在则抛出异常
w写模式,如果文件已存在,先清空原有内容
x写模式,创建新文件,如果文件已存在则抛出异常
a追加模式,不覆盖文件中原有模式
b二进制模式(可与其他模式组合使用)
t文本模式(默认模式,可省略)
+读、写模式(可与其他模式组合使用)

                 表6-1 文件打开模式

属性说明
closed判断文件是否关闭,若文件已关闭则返回True
mode返回文件的打开模式
name返回文件的名称

                 表6-2 文件对象的常用属性
  文件对象的常用方法如表6-3所示。特别说明的是读写操作相关的函数都会自动改变文件指针的位置。例如,以读模式打开一个文本文件,读取10个字符,会自动把文件指针移到第11个字符,再次读取字符的时候总是从文件指针的当前位置开始读取。

方法功能说明
flush()把缓冲区的内容写入文件,但不关闭文件
close()把缓冲区的内容写入文件,同时关闭文件,并释放文件对象
read([size])从文件中读取size个字节(Python 2.x)或字符(Python 3.x)的内容作为结果返回,如果省略size则表示读取所有内容。
readline()从文本文件中读取一行内容作为结果返回
readlines()把文本文件中的每行文本作为一个字符串存入列表中,返回该列表
seek(offset[,whence])把文件指针移到新的位置,offset表示相对于whence的位置。whence为0表示从文件头开始计算,1表示从当前位置开始计算,2表示从文件尾开始计算,默认为0
tell()返回文件指针的当前位置
truncate([size])删除从当前指针位置到文件末尾的内容。如果指定了size,则不论指针在什么位置都只留下前size个字节,其余的删除
write(s)把字符串s的内容写入文件
writelines(s)把字符串列表写入文本文件,不添加换行符
writable()测试当前文件是否可写
readable()测试当前文件是否可读

                 表6-3 文件对象的常用方法

二、文本文件操作案例精选

向文本文件中写入文件
s='Hello world\n 文本文件的读取方法\n文本文件的写入方法\n'
f=open('E:\python\sample.txt','a+')   #打开文件
f.write(s)    #写入文件内容
f.close()

文件操作一般都要遵循"打开文件-读写文件-关闭文件"的标准套路,但是如果文件读写操作代码引发了异常,很难保证文件能够被正确关闭,使用上下文管理关键字with可以避免这个问题。
关键字with可以自动管理资源,不论因为什么原因(哪怕是代码引发了异常)跳出with块,总能保证文件被正确关闭,并且可以在代码块执行完毕后自动还原进入该代码块时的现场,常用于文件操作、数据库连接、网络通信连接等场合。


with open('E:\文档\text.txt','a+')as f:
   f.write(s)
   
读取文本文件内容
fp=open('E:\文档\wlz.txt')
print(fp.read(4))     #从当前位置读取4个字符
print(fp.read(18))    #英文和汉字一样对待
print(fp.read())      #从当前位置读取后面的所有的内容
fp.close()  

读取并显示文本文件中的所有行
with open('E:\文档\wlz.txt')as fp:
    while True:
        line=fp.readline()
        if not line:
            break
        print(line)


with open('E:\文档\wlz.txt')as fp:
    for line in fp:               #文件对象是可以迭代的
        print(line) 
        
移动文件指针
fp=open('E:\文档\wlz.txt','r+')
print(fp.tell() )                      #返回文件指针的当前位置
print(fp.read(20))                     #读取20个字符
print(fp.seek(13))                     #重新定位文件指针的位置
print(fp.read(5))
fp.seek(13)
fp.write('测试')               #把文件指针当前位置写入内容
fp.flush()  #把缓冲区内容写入磁盘文件
fp.seek(0)
print(fp.read())
fp.close()                              #关闭文件

计算文本文件中最长行的长度和该行的内容

with open('E:\文档\wlz.txt')as fp:
    result=[0,'']
    for line in fp:
        t=len(line)
        if t>result[0]:
            result=[t,line]
print(result)

三、二进制文件操作案例精选

  数据库文件、图像文件、可执行文件、动态链接文件、音频文件、视频文件、Office文档等均属于二进制文件。
  对于二进制文件,不能使用记事本或其他文本编辑器软件直接进行正常读写,也不能通过Python的文件对象直接读取和理解二进制文件的内容。必须正确理解二进制文件的结构和序列化规则,然后设计正确的反序化规则。
  所谓序列化,简单的说就是把内存中的数据在不丢失其类型信息的情况下转换成对象的二进制形式的过程,对象序列化后的数据经过正确的反序列化过程应该能够准确无误地恢复为原来的对象。
Python中常用的序列化模块有struct、pickle、shelve、marshal和json,其中,json常用于文本信息的序列化。

使用pickle模块读写二进制文件

   Python标准库pickle提供的dump()方法用于将数据进行序列化并写入文件(dump()方法的protocol参数为True时可以实现压缩的效果),而load()用于读取二进制文件内容并进行反序列化,还原为原来的信息。

1.使用pickle模块写入二进制文件
n=7
i=13000000
a=99.056
s='中国人民 123abc'
lst=[[1,2,3],[4,5,6],[7,8,9]]
tu=(-5,10,8)
coll={4,5,6}
dic={'a':'apple','b':'banana','g':'grape','o':'orange'}
f=open('E:\文档\wlz.txt','wb')    #以写模式打开二进制文件
try:
    pickle.dump(n,f)    #对象个数
    pickle.dump(i,f)    #写入整数
    pickle.dump(a,f)    #写入实数
    pickle.dump(s,f)    #写入字符串
    pickle.dump(lst,f)  #写入列表
    pickle.dump(tu,f)   #写入元组
    pickle.dump(coll,f) #写入集合
    pickle.dump(dic,f)  #写入字典
except:
    print('写入文件异常')
finally:
    f.close()

2.使用pickle模块读取上例中写入的二进制文件的内容
f=open('E:\文档\wlz.txt','rb')    #独处文件的数据个数
n=pickle.load(f)
for i in range(n):
    x=pickle.load(f)
    print(x)
f.close()

3.pickle模块还提供了一个dumps()方法,可以返回对象序列化之后的字节形式。
print(pickle.dumps([1,2,3]))
print(pickle.dumps({1,2,3,4}))    #序列化集合
print(pickle.dumps((1,2,3)))      #序列化元组
print(pickle.dumps(123))          #序列化数字

下面的代码可以用来把文本文件转换为二进制文件,其中,wlz.txt是包含若干文本信息的源文件,sample.txt是转换后的二进制文件。

with open('E:\文档\wlz.txt')as src,open('E:\文档\sample.txt','wb')as dest:
    lines=src.readlines()
    pickle.dump(len(lines),dest)
    for line in lines:
        pickle.dump(line,dest)
with open('E:\文档\sample.txt','rb')as fp:
    n=pickle.load(fp)
    for i in range(n):
        print(pickle.load(fp))

使用struct模块读写二进制文件

使用struct模块需要使用pack()方法把对象按指定个数进行序列化,然后使用文件对象的write()方法将序列化的结果写入二进制文件;读取时需要使用文件对象的read()方法读取二进制文件内容,然后再使用struct模块的unpack()方法反序列化得到原来的信息。

1.使用struct模块写入二进制文件
n=1300000000
x=96.45
b=True
s='a1@中国'
sn=struct.pack('if?',n,x,b)    #序列化,i表示整数,f表示实数,?表示逻辑值
f=open('E:\文档\sample.txt','wb')
f.write(sn)
f.write(s.encode())            #字符串需要编码为字节串再写入文件
f.close()

2.使用struct模块读取上例中二进制文件的内容
f=open('E:\文档\sample.txt','rb')
sn=f.read(9)
tu=struct.unpack('if?',sn)       #使用指定格式反序列化
print(tu)
n,x,b1=tu
print('n=',n,'x=',x,'b1=',b1)
s=f.read(9)
s=s.decode()                      #字符串解码
print('s=',s)

上面的代码,大家会迷惑如何让确定要读取几个字节,为什么是9而不是其他数字

print(len(struct.pack('if?',13000,56.0,True)))
9
print(len('a1@中国'.encode()))
9

使用shelve模块操作二进制文件

Python标准库shelve也提供了二进制文件操作的功能,可以像字典赋值一样来写入二进制文件,也可以像字典一样读取二进制文件。

fp=shelve.open('sample.txt')   #创建或打开二进制文件
zhangsan={'age':38,'sex':'Male','address':'SDIBT'}
fp['zhangsan']=zhangsan         #写入文件内容
lisi={'age':40,'sex':'Male','qq':'1234567','tel':'7654321'}
fp['lisi']=lisi                 #写入文件内容
fp.close()
fp=shelve.open('sample.txt')
print(fp['zhangsan']['age'])    #查看文件内容
print(fp['lisi']['qq'])
fp.close()

使用marshal模块操作二进制文件

Python标准库marshal也可以进行对象的序列化和反序列化。

x1=30
x2=5.0
x3=[1,2,3]
x4=[4,5,6]
x5={'a':1,'b':2,'c':3}
x6={7,8,9}
x=[eval('x'+str(i))for i in range(1,7)]   #把需要序列化的对象放到放到一个列表中
print(x)
with open('E:\文档\wlz.txt','wb')as fp:   #创建二进制文件
    marshal.dump(len(x),fp)               #先写入对象个数
    for item in x:
        marshal.dump(item,fp)             #把列表中的对象依次序列化并写入文件

with open('E:\文档\wlz.txt','rb')as fp:   #打开二进制文件
    n=marshal.load(fp)                    #获取对象个数
    for i in range(n):
        print(marshal.load(fp))


文件与文件夹操作

标准库os、os.path与shutil简介

os模块除了提供使用操作系统功能和访问文件系统的简便方法之外,还提供了大量文件与文件夹操作的方法。
os.path模块提供了大量用于路径判断、切分、连接以及文件夹遍历的方法。
shutil模块也提供了大量的方法支持文件和文件夹操作。

方法功能说明
access(path,mode)按照mode指定的权限访问文件
chdir(path)把path设为当前工作目录
chmod改变文件的权限访问
extsep当前操作系统所使用的文件扩展名分隔符
fstat(path)返回打开的文件的所有属性
get_exec_path()返回可执行文件的搜索路径
getcwd()返回当前工作目录
listdir(path)返回path目录下的文件和目录列表
mkdir(path[,mode=0777])创建目录
makedirs(path1/path2…,mode=511)创建多级目录
open(path,flags,mode=0o777,*,dir_fd=None)按照mode指定的权限打开文件,默认权限为可读、可写、可执行
rmdir(path)删除目录,目录中不能有文件或子文件夹
remove(path)删除指定的文件
rename(src,dst)重命名文件或目录,可实现文件的移动
scandir(path=’. ')返回包含指定文件夹中所有DirEntry对象的迭代对象
sep当前操作系统所使用的路径分隔符
startfile(filepath[,operation])使用关联的应用程序打开指定文件或启动指定应用程序
stat(path)返回文件的所有属性
truncate(path,length)将文件截断,只保留指定长度的内容
walk(top,topdown=True,οnerrοr=None)遍历目录树,该方法返回一个元组,包括3个元素;所有路径名、所有目录列表与文件列表
write(fd,data)将bytes对象data写入文件fd

                     os模块常用成员

方法功能属性
abspath(path)返回给定路径的绝对路径
basename(path)返回指定路径的最后一个组成部分
commompath(paths)返回给定的多个路径的最长公共路径
commonprefix(paths)返回给定的多个路径的最长公共前缀
dirname§返回给定路径的文件夹部分
exists(path)判断文件是否存在
getatime(filename)返回文件的最后访问时间
getctime(filename)返回文件的创建时间
getmtime(filename)返回文件的最后修改时间
getsize(filename)返回文件的大小
isabs(path)判断path是否为绝对路径
isdir(path)判断path是否为文件夹
isfile(path)判断path是否为文件
join(path,*paths)连接两个或多个path
split(path)对路径进行分隔,以列表形式返回
splitext(path)从路径中分隔文件的扩展名
splitdrive(path)从路径中分隔驱动器的名称

                os.path模块常用成员

方法功能说明
copyfile(src,dst复制文件
copytree(src,dst)递归复制文件夹
disk_usage(path)查看磁盘使用情况
move(src,dst)移动文件或递归移动文件夹
rmtree(path)移动文件或递归移动文件夹
make_archive创建tar或zip格式的压缩文件
unpack_archive解压缩文件

                shutil模块常用成员

print(os.path.basename('E:\文档\wlz.txt'))     #获取路径的最后一个组成部分
print(os.path.exists('E:\文档\wlz.txt'))       #测试文件是否存在
os.rename('E:\文档\wlz_new.txt','E:\文档\wlz_new2.txt')
path='E:\文档\wlz.txt'
print(os.path.dirname(path))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值