进阶篇已发布,请戳:谈妖:Python文件IO大杂烩(二):进阶zhuanlan.zhihu.com
本篇主要为IO操作的基础部分,涉及部分文件指针等内容。下篇将会总结IO的进阶部分,包括路径操作、部分io模块、序列化与反序列化等内容。
文件io是指文件内容的输入和输出,常用操作包括打开文件、读取、写入、关闭等,下面将对其进行逐一讲解。
open 打开文件
使用open函数,我们可以打开文件并对其进行操作,open函数的形式如下:
open(file,mode='r',buffering=-1,encoding=None,errors=None,newline=None,closed=True,opener=None)
该函数可以打开一个文件并返回文件对象和描述符。我们可以按照如下示例使用该函数:
f = open('text')
f.close()
在上例中,我们创建了一个文件对象text,并将其关闭。
open函数有非常多的参数,了解这些参数,就了解了open函数的用法。
下面我们将按照顺序对这些参数进行介绍。
file
file是你需要打开的文件,可以通过路径+文件名指定,只填写文件名则默认是在当前目录下。
在上面案例中创建的text文件就会在当前目录创建一个文件。
mode
mode参数非常重要,表示以何种形式打开文件。
其默认值为r,即是只读模式,在这种模式下只能进行读取,写入会报错。
mode一共有以下七个参数:r mode缺省值,表示只读模式打开,文件不存在会抛出异常
w 只写模式打开,会将文件内容清空重写,文件不存在则创建
x 若文件不存在,创建新文件并以只写模式打开,文件存在则抛出异常
a 只写模式打开,不会清空文件内容,而是会从现有内容后面写入,文件不存在则创建文件
b 二进制模式打开,需要配合前四个参数之一使用
t 文本模式打开,需要配合前四个参数之一使用
+ 为现有模式增强功能,只读则增加写入,反之亦然,配合前四个参数之一使用
注意:前四个参数无法共存
在上述的模式中,文件被打开后会有一个指针指向文件的某个位置,我们将其称为文件指针。
使用tell函数可以显示当前指针的位置。
>>> f=open('test','r')
>>> f.tell()
0
使用r模式打开时,文件指针指向0,即文档开始处,因此读取操作会从文件开始处向后进行。
>>> f= open('test','w')
>>> f.tell()
0
使用w模式打开时,文件指针指向0,因此w会清除文件内容后从开始处写入新内容。
>>> f = open('test','x')
>>> f.tell()
0
使用x模式打开时,文件指针指向0,因此创建文件后从文件开始处向后写入。
>>> f= open('tset','a')
>>> f.tell()
7
使用a模式打开时,文件指针实际上指向EOF处,即 end of file,文件结尾处,因此a将从文件结尾处继续写入。
文件指针的位置可以通过seek函数,该函数在文本模式下和二进制模式下用法略有不同。
文本模式
seek(offest[,whence])
offest参数表示指针偏移的字节数,whence表示指针开始的位置。
whence 缺省参数为0,表示从头开始,offset参数必须为正整数,表示向后调节的字节数。
whence 为1,表示从当前位置开始,offset只能为0。
whence 为2,表示从EOF开始,offset只能为0。
二进制模式
offest参数表示指针偏移的字节数,whence表示指针开始的位置。
whence 缺省参数为0,表示从头开始,offset参数必须为正整数,表示向后调节的字节数。
whence 为1,表示从当前位置开始,offset可正可负。
whence 为2,表示从EOF开始,offset可正可负。
offset为负值时表示向前迁移的位数,超过最大限度后抛出异常。
buffering
正常情况下,程序运行在内存中,io操作也不例外。而buffer缓冲区就是一个内存空间,它可以视为一个FIFO(先进先出)队列,当缓冲区达到阈值或者满了的时候,数据会被flush到磁盘。
buffering 的缺省值为-1,表示使用默认大小的缓冲区(io.DEFAULT_BUFFER_SIZE),二进制模式下一般为4096或8192,文本模式视情况而定(终端设备是行缓冲,否则同样是默认大小缓冲区)。
buffering=0,仅支持二进制模式,关闭缓冲区。
buffering=1,二进制模式下缓冲区设为一个字节,文本模式下设为行缓冲。
buffering>1,二进制模式下表示缓冲区大小。
查看示例:
f = open('test','w+b')
f.write(b'abcdef')
执行上述程序后查看文件,文件为空。
调用f.close()后查看文件,文件内有'abcdef'字符。
我们尝试设置缓冲区:
f = open('test','w+b',4)
f.write(b'abcdef')
执行上述程序后查看文件,文件内有'abcdef'字符。
原因在于我们将缓冲区设为4个字节,write函数写入了6个字节,超出了缓冲区大小,因此整个字符串被flush到磁盘,我们可以在未执行close函数时在文件内看到字符串。
除非明确知道缓冲区所需大小,一般建议使用默认的缓冲区设置。
平时我们会遇到很多有即时保存需求的数据,此时我们可以调用flush函数立刻将其flush到磁盘,即使其长度未能达到缓冲区大小或阈值。
查看示例:
f = open('test','w+b')
f.write(b'abcdef')
f.flush()
此时查看文件,发现文件内已有字符串'abcdef'。
你也许注意到,即使不调用flush函数,关闭文件后文件内也会写入相应内容。这是因为关闭文件前,close函数会调用flush函数。
encoding
encoding参数表示打开文件时使用何种编码,缺省时根据操作系统决定。
windows系统是GBK编码,linux系统是UTF-8编码。
errors
如何接受编码错误。
None 和 strict 表示在编码错误是抛出ValueError异常,ignore会忽略错误。
newline
文本模式下指定换行符。
可接受None、"、'\r'、'\n'、'\r\n'。
读取模式下,None 表示'\r'、'\n'、'\r\n'这三种换行符都会被替换为'\n',"表示不会自动替换换行符,其他字符表示以该字符为分隔符换行。
写入模式下,None 表示'\n'会被替换为系统默认换行符,'\n'和"表示'\n'不替换,其他合法字符将会自动替换'\n'。
closdfd
文件关闭后是否关闭文件描述符。
True表示关闭,False表示不关闭。
read
read函数用于读取文件。
其基本形式是:
read(size=-1)
size表示读取的字符或字节数,为 None 或负数时读取到EOF。
示例如下:
>>> f =open(test,'w+')
>>> f.write('abcdefg')
7
>>> f.seek(0)
0
>>> f.read(4)
'abcd'
>>> f.close()
readline
一行一行读取文件。
其基本形式:
readline(size=-1)
size表示一次读取行内的几个字符或字节,None
或者负数时读取到行尾。
其用法类似于read,不再过多展示。
readlines
读取所有行。
其基本形式:
readlines(hint=-1)
hint表示一次返回多少行的内容,None 或者负数时读取到EOF。
其用法类似于read,不再过多展示。
write
向文件内写入内容。仅当可写时生效。
其基本形式:
write(s)
s为需要写入的字符串,该函数返回写入的字符数或字节数。
close
调用flush函数并关闭文件对象。
上下文管理
文件需要在内存中操作,打开过多的文件可能会占用过多的内存资源。此外,linux 系统默认限制了文件打开的数量(一般为1024),超过数量限制就会报错。
为了解决这种问题,我们需要通过上下文管理减少同时打开的文件数量。
所谓上下文管理其实是一种特殊的语法,通过'with...as...'语句,让解释器去自动的关闭对象。
示例:
>>> with open(f1) as f:
... f.read()
...
'abcdefg'
>>> f.closed
True
在with语句执行完之后,文件会被自动关闭。
其他操作
seekable() 是否可以改变指针
readable() 是否可读
writeable() 是否可写
closed 是否关闭
扩展知识
除了文件对象之外,io模块还提供 StringIO 和 ByetsIO 两个类。(注意类名称的大小写)
两个类基本可以使用文件IO的所有方法,同时还有getvalue这个无视指针输出所有内容的方法。
StringIO 和 ByetsIO实际上是直接在内存中开辟一个buffer,因此操作效率比涉及到磁盘的IO要高得多。