<< >>

diveintopython.org |

Python for experienced programmers

## 3.10. 文件对象

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

例 3.19. 打开文件

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

| `open` 方法可以接收三个参数：文件名，模式，和缓冲区参数。只有第一个参数，文件名，是必须的；其它两个是可选的。如果没有指定，文件以文本方式打开。这里我们以二进制方式打开文件进行读取。(`print open.__doc__` 会给出所有可能模式的很好的解释。)
| `open` 函数返回一个对象(到现在为止，这一点应该不会使你感到吃惊)。一个文件对象有几个有用的属性。
| 文件对象的 `mode` 属性告诉你文件以何种模式被打开。
| 文件对象的 `name` 属性告诉你文件对象所打开的文件名。

例 3.20. 读取文件

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

| 一个文件对象维护它所打开文件的状态。文件对象的 `tell` 方法告诉你在打开文件中的当前位置。因为我们还没有对这个文件做任何事，当前位置为 `0`，它是文件的开始处。
| 文件对象的 `seek` 方法在打开文件中移动到另一个位置。第二个参数指出第一个参数是什么意思：`0` 表示移动到一个绝对位置(从文件开始算起)，`1` 表示移到一个相对位置(从当前位置算起)，还有 `2` 表示对于文件尾的一个相对位置。因为我们搜索的MP3标记保存在文件的末尾，我们使用 `2` 并且告诉文件对象从文件尾移动到`128` 字节的位置。
| `tell` 方法确认了已经移到当前文件位置。
| `read` 方法从打开文件中读取指定个数的字节，并且返回含有读取数据的字符串。可选参数指定了读取的最大字节数。如果没有指定参数，`read` 将读到文件末尾。(我们本可以在这里简单地说一下 `read()`，因为我们确切地知道在文件的何处，事实上，我们读的是最后128个字节。)读出的数据赋给变量 `tagData`，并且当前的位置根据所读的字节数作了修改。
| `tell` 方法确认了当前位置已经移动了。如果做一下算术，你会看到在读了128个字节之后，位置数已经增加了128。

例 3.21. 关闭文件

    >>> f
    <open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>
    >>> f.closed
    0
    >>> f.close()
    >>> f
    <closed file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>
    >>> f.closed
    1
    >>> f.seek(0)
    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()

| 文件对象的 `closed` 属性表示对象是否打开或关闭了文件。在本例中，文件仍然打开着(`closed` 是 `0`)。打开文件要消耗系统资源，并且根据文件模式，其它程序可能不能使用它们。一旦你处理完它们，把文件关闭这一点很重要。
| 为了关闭文件，调用文件对象的 `close` 方法。这样就释放掉你加在文件上的锁(如果有的话)，刷新被缓冲的系统确实还未写入的输出(如果有的话)，并且翻放系统资源。`closed` 属性证实了文件被关闭了。
| 只是因为文件被关闭，并不意味着文件对象停止存在。变量 `f` 将继续存在，直到它超出作用域或被手工删除。然而，一旦文件被关闭，可操作打开文件的方法没有一个能使用；它们都会引发异常。
| 对一个文件已经关闭的文件对象调用 `close` 不会引发异常，它静静地失败。

例 3.22. `MP3FileInfo` 中的文件对象

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

| 因为打开和读取文件有风险，并且可能引发异常，所有这些代码都用一个 `try...except` 块封装。(嘿，标准化的缩排不好吗？这就是你开始欣赏它的地方。)
| `open` 函数可能引发 `IOError` 异常。(可能是文件不存在。)
| `seek` 方法可能引发 `IOError` 异常。(可能是文件长度小于128字节。)
| `read` 方法可能引发 `IOError` 异常。(可能磁盘有坏扇区，或它在一个网络驱劝器上，而网络刚好断了。)
| 这是新的：一个 `try...finally` 块。一旦文件通过 `open` 函数被成功地打开，我们应该绝对保证把它关闭，甚至由于 `seek` 或 `read` 方法引发了一个异常。`try...finally` 块可以用来：在 `finally` 块中的代码将总被执行，甚至某些东西在 `try` 块中引发一个异常也会执行。可以这样考虑，不管在路上发生什么，代码都会被“即将灭亡”地执行。
| 最后，处理我们的 `IOError` 异常。它可能是由调用 `open`，`seek`，或 `read` 引发的 `IOError` 异常。这里，我们其实不关心，因为将要做的事就是静静地忽略它然后继续。(记住，`pass` 是一条不做任何事的Python语句。)这样完全合法，“处理”一个异常可以明确表示不做任何事。它仍然被认为处理过了，并且处理将正常继续，从 `try...except` 块的下一行代码。

进一步阅读 |

- Python Tutorial 讨论了文件的读取和写入，包括如何将一个文件一次一行地读到列表中。
- eff-bot 讨论了各种各样读取文件方法的效率和性能。
- Python Knowledge Base 回答了关于文件的常见问题。
- Python Library Reference 总结了所有文件对象模块。

« 处理异常 | for 循环 »