[TOC]
before
本小节介绍一个特殊的函数——open函数,因为到目前为止,我们写的程序都非常的简陋,应用范围狭窄,而通过open函数,我们就可以将程序得以扩展到文件和流的领域。
打开文件
通过open函数打开文件,其语法如下:
open(
file,
[mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True]
)open函数打开文件或文件描述符并返回文件对象,如果无法打开则抛出OSError错误。
file参数为字符串或者是字节对象的路径或者相对路径(当前工作目录)。
buffering参数控制着文件的缓冲,如果参数是0或者False,那么就是说无缓冲,所有的读写操作都是直接针对硬盘的操作。如果参数是1或者True,那么意为Python会使用内存代替硬盘,从而让程序变得更快,只有使用flush或者close时,缓冲区的文件才会更新到硬盘。
encoding参数指以什么方式操作文件,该参数只适用于文本模式。
errors参数指定如何处理编码和解码错误。仅适用于文本模式。
newline参数为换行符控制换行符模式的工作方式,仅适用于文本模式,如果该参数为None,那么它的工作方式是,从文件流中读取输入时,启用通用换行符模式,将所有的换行符(\r\n 或者\n)转换为\n,再返回给调用者。
closefd参数为True时,则为传入file参数为文件的文件名。为False时传入的file参数只能是文件描述符。什么是文件描述符?在UNIX平台的系统中,文件描述符就是一个非负数,比如说,打开一个文件,就会得到一个文件描述符。
mode为可选参数,用于指定打开文件的模式,默认为r,以读的方式打开文件,常用的mode模式如下所示:
| mode | 描述 |
|---|---|
| r | 打开文件,以读的方式,默认的方式 |
| w | 以写的方式打开文件,如果原文件存在则会被覆盖,如果没有此文件就会创建,前提是该模式下必须保证文件目录的存在 |
| a | 以追加的方式打开文件,如果文件存在则从原文件的末尾写入,否则会创建文件 |
| rb | 打开文件,以二进制的形式读文件 |
| ab | 以二进制追加模式打开文件 |
| wb | 以二进制写模式打开,打开前原文件会被清空 |
一般地,如果Python处理的是文本文件,使用r、w模式没有任何问题。但有时会处理一些其他类型文件(二进制文件),如音、视频文件,那么就应该在模式参数中增加b模式,如rb模式读取二进制文件。那么为什么使用rb模式?
如果使用rb模式,通常跟r模式不会有太大区别,仍然是读取一定的字节,并且能执行文本文件的相关操作。Python使用二进制模式关键点是给出原样的文件。而文本模式下则不一定。
因为在于Python对于文本文件的操作方式有些不同,其中就有标准化换行符。一般的,Python的标准换行符是\n,表示结束一行并另起一行,这也是UNIX系统的规范。而Windows系统中则是\r\n,但无需担心,Python会自动在各平台间(包括Mac平台)帮我们转换。但这并不足以解决问题,因为二进制文件中(音、视频)很可能包含这些换行符。如果Python以文本模式处理这些文件,那么很可能就破坏了文件。为了避免此类问题,就要以二进制的方式操作这些文件,这样在操作中就不会发生转换从而避免文件损坏。
如果在读的时候以通用的模式读取文件,则所有的文件都统一转换为\n,从而不用考虑平台问题。
open函数常用的参数为file、encoding、mode三个参数。
常用方法
既然打开了文件,就要对文件做些什么了!接下来介绍文件对象的一些方法。
对文件的操作最重要的就是读和写了,那么拿到一个文件对象f时,通过f.read和f.write两个方法完成读写操作。
w模式和write
f1 = open('t1.txt', mode='w')
f1.write('hello')
f1.write('world')
f1.close()上例,open函数以写的方式打开t1.txt文件并将文件句柄f1返回,w模式的特点是如果文件不存在就创建文件,文件存在就覆盖写,并且这个文件句柄只能写入普通的文本字符串(写入bytes类型的文件会报错)。通过文件句柄调用写方法将两个字符串写入文件中,然后关闭文件句柄。此时如果你打开t1.txt文件的话,会发现这两个字符串紧挨着在一行上。这是因为两个字符串之间没有换行符\n。
来,我们加上换行符:
f1 = open('t1.txt', mode='w')
f1.write('hello\n')
f1.write('world\n')
f1.close()现在,这两个字符串各占一行了。
r模式和read系列
那么如何读文件呢?
f2 = open('t1.txt', mode='r')
content = f2.read()
print(content)
f2.close()
"""
hello
world
"""上例,首先以读模式拿到文件句柄f2,然后使用read方法一次性读取t1.txt内的所有内容。注意,r模式读取普通的文本字符串(读取bytes类型的文本文件会报错)。最后关闭文件句柄。
这里思考一个问题,read是一次性的读取所有文件内容,但如果文件特别大的话,比如有两个G的日志文件,将这么大的文件一次性的读取到内存中,是不合理的,所以,可以在read的时候指定每次读的字节数大小:
f3 = open('t1.txt', mode='r')
content = f3.read(5)
print(content)
content = f3.read(5)
print(content)
f3.close()
"""
hello
worl
"""上例,当第一次读的时候,读了5个字节的内容hello,第二次读的时候,从第一次读的位置后面继续往后读5个字节,首先读到了一个换行符\n,然后在读第二行的四个字节worl。
除了在read,还有其他的读方法:
f4 = open('t1.txt', mode='r')
content = f4.readline()
print(content)
f4.close()
f5 = open('t1.txt', mode='r')
content = f5.readlines()
print(content)
f5.close()
"""
hello
['hello\n', 'world\n']
"""上例,readline每次读一行(两次打印结果之间的空行是第一行的\n),readlines读取所有行,并以列表的形式返回。
a模式
有些情况不能覆盖写,而是要追加写,比如日志文件,这就用到了a模式——追加写:
f6 = open('t1.txt', 'a')
for i in "hello":
f6.write('{}{}'.format(i, '\n'))
f6.close()追加写模式中,如果文件存在,则以追加的方式继续写入,如果文件不存在就创建文件,然后以追加的方式写入。
wb/ab/rb
之前处理的都是文本字符串,要处理音视频、图片等二进制类型的文件时,就需要搭配使用b模式了,b模式标识处理的是二进制文件:
f7 = open('t1.png', 'rb')
content = f7.read()
f8 = open('t2.png', 'wb')
f8.write(content)
f7.close()
f8.close()上例,要处理的是图片类型的文件,所以要使用b模式来读写。如果要传输的是视频之类的,就要考虑使用ab模式了。
seek/tell
除了上面read系列的顺序读取文件,Python还提供了随机读取文件方法:
f9 = open('t1.txt', 'r')
print(f9.tell())
f9.seek(2)
print(f9.tell())
content = f9.read()
print(content)
print(f9.tell())
f9.close()
"""
0
2
llo
world
12
"""上例,seek(offset, [whence])方法意为把当前读(或写)的位置移动到由offset和whence定义的位置,offset表示偏移的字节量,而whence为可选参数,搭配offset使用,表示从哪个位置开始偏移,0表示从文件开头开始,1代表从当前位置开始开始,2表示从文件末尾开始偏移。 而tell方法则返回当前指针所在的位置。
关闭文件
我们为什么在对文件对象f操作完毕之后,都要去关闭它?
f14 = open('t1.txt', 'w')
f14.write('hello\n')
# f14.close()
f15 = open('t1.txt', 'r')
content = f15.read()
print(content)上例,如果f14文件句柄不关闭,f15文件句柄则无法读取文件内容。这只是其中一种情况。
有时候,Python解释器因为某些原因如提高程序运行速度,会将文件缓存在内存中某个地方。但碰到意外如程序突然崩溃,就会造成这些缓存数据没有及时写入硬盘。也为了降低系统对打开文件的资源占用,如在Linux系统中,对打开文件数会有限制,超过限制则无法打开文件。为了避免这些可能出现的问题,在对文件处理完毕之后及时关闭文件。
而关闭文件则有两种方式,一起来看看吧!
手动关闭文件
手动关闭就是使用f.close来完成。这无需多说了:
f14 = open('t1.txt', 'w')
f14.write('hello\n')
f14.close()
f15 = open('t1.txt', 'r')
content = f15.read()
print(content)
f6.close()自动关闭文件
但每次都手动关闭文件,比较麻烦,Python又提供了with语句来解决这个麻烦。
with语句:
with open(...) as f:
f.read()open函数的参数不变,关键字as后面的文件对象f可以自定义。
with语句允许使用上下文管理器,上下文管理器则是支持__enter__与__exit__方法的对象。__enter__方法没有参数,当程序执行到with语句的时候被触发,返回值绑定在文件对象f上。而__exit__方法则有三个参数,包括异常类型、异常对象、异常回溯。现在无需深入了解这个三个参数,只需知道当with语句执行完毕,也就是对文件的操作执行完毕,with会自动执行__exit__方法来关闭文件。
来个示例:
with open('t1.txt', 'w') as f:
f.write('with 语句真省事')
with open('t1.txt', 'r') as f:
f.read() # with 语句真省事with语句无疑帮我们做了很大的工作,让我们专心于文件操作本身。
当然了,with语句的功能不仅限于此,它还有其他的用法,这里不做过多的探讨。
f是什么?
我们对一个文件操作,总是要拿到这个文件句柄来做操作,那么这个文件句柄是什么呢?
from collections import Iterable
f = open('t1.txt', 'r')
print(isinstance(f, Iterable)) # True由上例可以看到,文件句柄f它也是一个可迭代对象,那么我们就可以通过循环来取值。
f = open('t1.txt', 'r')
for i in f:
print(i)
"""
hello
world
"""每次循环读取一行数据。