diveintopython.org
Python for experienced programmers

3.10. 文件对象

Python有一个内置函数,open,用来打开在磁盘上的文件。open 返回一个文件对象,它拥有一些方法和属性,可以得到打开文件的信息,和对打开文件进行操作。

例 3.19. 打开文件

>>> f = open("/music/_singles/kairo.mp3", "rb") 1
>>> f                                           2
<open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>
>>> f.mode                                      3
'rb'
>>> f.name                                      4
'/music/_singles/kairo.mp3'
1

open 方法可以接收三个参数:文件名,模式,和缓冲区参数。只有第一个参数,文件名,是必须的;其它两个是可选的。如果没有指定,文件以文本方式打开。这里我们以二进制方式打开文件进行读取。(print open.__doc__ 会给出所有可能模式的很好的解释。)

2 open 函数返回一个对象(到现在为止,这一点应该不会使你感到吃惊)。一个文件对象有几个有用的属性。
3 文件对象的 mode 属性告诉你文件以何种模式被打开。
4 文件对象的 name 属性告诉你文件对象所打开的文件名。

例 3.20. 读取文件

>>> f
<open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>
>>> f.tell()              1
0
>>> f.seek(-128, 2)       2
>>> f.tell()              3
7542909
>>> tagData = f.read(128) 4
>>> tagData
'TAGKAIRO****THE BEST GOA         ***DJ MARY-JANE***            Rave Mix                      2000http://mp3.com/DJMARYJANE     \037'
>>> f.tell()              5
7543037
1

一个文件对象维护它所打开文件的状态。文件对象的 tell 方法告诉你在打开文件中的当前位置。因为我们还没有对这个文件做任何事,当前位置为 0,它是文件的开始处。

2

文件对象的 seek 方法在打开文件中移动到另一个位置。第二个参数指出第一个参数是什么意思:0 表示移动到一个绝对位置(从文件开始算起),1 表示移到一个相对位置(从当前位置算起),还有 2 表示对于文件尾的一个相对位置。因为我们搜索的MP3标记保存在文件的末尾,我们使用 2 并且告诉文件对象从文件尾移动到 128 字节的位置。

3 tell 方法确认了已经移到当前文件位置。
4

read 方法从打开文件中读取指定个数的字节,并且返回含有读取数据的字符串。可选参数指定了读取的最大字节数。如果没有指定参数,read 将读到文件末尾。(我们本可以在这里简单地说一下 read(),因为我们确切地知道在文件的何处,事实上,我们读的是最后128个字节。)读出的数据赋给变量 tagData,并且当前的位置根据所读的字节数作了修改。

5

tell 方法确认了当前位置已经移动了。如果做一下算术,你会看到在读了128个字节之后,位置数已经增加了128。

例 3.21. 关闭文件

>>> f
<open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>
>>> f.closed  1
0
>>> f.close() 2
>>> f
<closed file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>
>>> f.closed
1
>>> f.seek(0) 3
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: I/O operation on closed file
>>> f.tell()
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: I/O operation on closed file
>>> f.read()
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: I/O operation on closed file
>>> f.close() 4
1

文件对象的 closed 属性表示对象是否打开或关闭了文件。在本例中,文件仍然打开着(closed0)。打开文件要消耗系统资源,并且根据文件模式,其它程序可能不能使用它们。一旦你处理完它们,把文件关闭这一点很重要。

2

为了关闭文件,调用文件对象的 close 方法。这样就释放掉你加在文件上的锁(如果有的话),刷新被缓冲的系统确实还未写入的输出(如果有的话),并且翻放系统资源。closed 属性证实了文件被关闭了。

3

只是因为文件被关闭,并不意味着文件对象停止存在。变量 f 将继续存在,直到它超出作用域或被手工删除。然而,一旦文件被关闭,可操作打开文件的方法没有一个能使用;它们都会引发异常。

4

对一个文件已经关闭的文件对象调用 close 不会引发异常,它静静地失败。

例 3.22. MP3FileInfo 中的文件对象

        try:                                1
            fsock = open(filename, "rb", 0) 2
            try:                           
                fsock.seek(-128, 2)         3
                tagdata = fsock.read(128)   4
            finally:                        5
                fsock.close()              
            .
            .
            .
        except IOError:                     6
            pass                           
1

因为打开和读取文件有风险,并且可能引发异常,所有这些代码都用一个 try...except 块封装。(嘿,标准化的缩排不好吗?这就是你开始欣赏它的地方。)

2 open 函数可能引发 IOError 异常。(可能是文件不存在。)
3 seek 方法可能引发 IOError 异常。(可能是文件长度小于128字节。)
4 read 方法可能引发 IOError 异常。(可能磁盘有坏扇区,或它在一个网络驱劝器上,而网络刚好断了。)
5

这是新的:一个 try...finally 块。一旦文件通过 open 函数被成功地打开,我们应该绝对保证把它关闭,甚至由于 seekread 方法引发了一个异常。try...finally 块可以用来:在 finally 块中的代码将被执行,甚至某些东西在 try 块中引发一个异常也会执行。可以这样考虑,不管在路上发生什么,代码都会被“即将灭亡”地执行。

6

最后,处理我们的 IOError 异常。它可能是由调用 openseek,或 read 引发的 IOError 异常。这里,我们其实不关心,因为将要做的事就是静静地忽略它然后继续。(记住,pass 是一条不做任何事的Python语句。)这样完全合法,“处理”一个异常可以明确表示不做任何事。它仍然被认为处理过了,并且处理将正常继续,从 try...except 块的下一行代码。


进一步阅读