9.3 文件内建方法

    open()成功执行并返回一个文件对象之后,所有对该文件的后续操作都将通过这个“句柄”进行。文件方法可以分为四类:输入、输出、文件内移动及杂项操作。所有文件对象的总结被列在了表9.3中。我们现在来讨论每个类的方法。

    9.3.1 输入

    read()方法用来直接读取字节到字符串中,最多读取给定数目个字节。如果没有给定size参数(默认值为-1)或者size值为负,文件将被读取直至末尾。未来的某个版本可能会删除此方法。

    readline()方法读取打开文件的一行(读取下个行结束符之前的所有字节)。然后整行,包括行结束符,作为字符串返回。和read()相同,它也有一个可选的size参数,默认为-1,代表读至行结束符。如果提供了该参数,那么在超过size个字节后会返回不完整的行。

    readlines()方法并不像其他两个输入方法一样返回一个字符串。它会读取所有(剩余的)行然后把它们作为一个字符串列表返回。它的可选参数sizhint代表返回的最大字节大小。如果它大于0,那么返回的所有行应该大约有sizhint字节(可能稍微大于这个数字,因为需要凑齐缓冲区大小)。

    Python 2.1中加入了一个新的对象类型用来高效地迭代文件的行:xreadlines对象(可以在 xreadlines模块中找到)。调用file.xreadlines()等价于xreadlines.xreadlines(file)。xreadlines()不是一次性读取所有的行,而是每次读取一块,所以用在for循环时可以减少对内存的占用。不过,随着Python 2.3中迭代器和文件迭代的引入,没有必要再使用xreadlines()方法,因为它和使用iter(file)的效果是一样的,或者在for循环中,使用for eachLine in file代替它。它来得容易,去得也快。

    另一个废弃的方法是readinto(),它读取给定数目的字节到一个可写的缓冲器对象,和废弃的buffer()内建函数返回的对象是同个类型(由于buffer()已经不再支持,所以readinto()被废弃)。

    9.3.2 输出

    write()内建方法的功能与read()和readline()相反。它把含有文本数据或二进制数据块的字符串写入到文件中去。

    和readlines()一样,writelines()方法是针对列表的操作,它接受一个字符串列表作为参数,将它们写入文件。行结束符并不会被自动加入,所以如果需要的话,你必须在调用writelines()前给每行结尾加上行结束符。

    注意这里并没有“writeline()”方法,因为它等价于使用以行结束符结尾的单行字符串调用write()方法。

    9.3 文件内建方法 - 图1核心笔记:保留行分隔符


    当使用输入方法如read()或者readlines()从文件中读取行时,Python并不会删除行结束符,这个操作被留给了程序员。例如这样的代码在Python程序中很常见:

    9.3 文件内建方法 - 图2

    类似地,输出方法write()或writelines()也不会自动加入行结束符。你应该在向文件写入数据前自己完成。


    9.3.3 文件内移动

    seek()方法(类似C中的fseek()函数)可以在文件中移动文件指针到不同的位置。offset字节代表相对于某个位置偏移量。位置的默认值为0,代表从文件开头算起(即绝对偏移量),1代表从当前位置算起, 2代表从文件末尾算起。如果你是一个C程序员,并且使用过了fseek(),那么,0、1、2分别对应着常量 SEEK_SET、SEEK_CUR和SEEK_END。当人们打开文件进行读写操作的时候就会接触到seek()方法。

    text()方法是对seek()的补充;它告诉你当前文件指针在文件中的位置——从文件起始算起,单位为字节。

    9.3.4 文件迭代

    一行一行访问文件很简单:

    9.3 文件内建方法 - 图3

    :

    在这个循环里,eachLine代表文本文件的一行(包括末尾的行结束符),你可以使用它做任何想做的事情。

    在Python 2.2之前,从文件中读取行的最好办法是使用file.readlines()来读取所有数据,这样程序员可以尽快释放文件资源。如果不需要这样做,那么程序员可以调用file.readline()一次读取一行。曾有一段很短的时间,file.xreadlines()是读取文件最高效的方法。

    在Python 2.2中,我们引进了迭代器和文件迭代,这使得一切变得完全不同,文件对象成为了它们自己的迭代器,这意味着用户不必调用read*()方法就可以在for循环中迭代文件的每一行。另外我们也可以使用迭代器的next方法,file.next()可以用来读取文件的下一行。和其他迭代器一样,Python也会在所有行迭代完成后引发Stoplteration异常。

    所以请记住,如果你见到这样的代码,这是“完成事情的老方法”,你可以安全地删除对readline()的调用。

    9.3 文件内建方法 - 图4

    :

    文件迭代更为高效,而且写(和读)这样的Python代码更容易。如果你是Python新手,那么请使用这些新特性,不必担心它们过去是如何。

    9.3.5 其他

    close()通过关闭文件来结束对它的访问。Python垃圾收集机制也会在文件对象的引用计数降至零的时候自动关闭文件。这在文件只有一个引用时发生,例如fp=open(…),然后fp在原文件显式地关闭前被赋了另一个文件对象。良好的编程习惯要求在重新赋另一个文件对象前关闭这个文件。如果你不显式地关闭文件,那么你可能丢失输出缓冲区的数据。

    fileno()方法返回打开文件的描述符。这是一个整型,可以用在如os模块(os.read())的一些底层操作上。

    调用flush()方法会直接把内部缓冲区中的数据立刻写入文件,而不是被动地等待输出缓冲区被写入。isatty()是一个布尔内建函数,当文件是一个类tty设备时返回True,否则返回False。truncate()方法将文件截取到当前文件指针位置或者到给定size,以字节为单位。

    9.3.6 文件方法杂项

    我们现在重新实现第2章中的第一个文件例子:

    9.3 文件内建方法 - 图5

    我们曾经介绍过这个程序。与大多数标准的文件访问方法相比,它的不同在于它读完所有的行才开始向屏幕输出数据。很明显如果文件很大,这个方法并不好。这时最好还是回到最可靠的方法:使用文件迭代器,每次只读取和显示一行:

    9.3 文件内建方法 - 图6

    9.3 文件内建方法 - 图7核心笔记:行分隔符和其他文件系统的差异

    操作系统间的差异之一是它们所支持的行分隔符不同。在POSIX(Unix系列或MacOS X)系统上,行分隔符是换行符NEWLINE ( \n)字符。在旧的MacOS下是RETURN( \r),而DOS和Wind32系统下结合使用了两者 (\r\n)。检查一下你所使用的操作系统用什么行分隔符。
    另一个不同是路径分隔符(POSIX使用“/”; DOS和Windows使用“\”;旧版本的MacOS使用“:”);它用来分隔文件路径名;标记当前目录和父目录。当我们创建要跨这3个平台的应用的时候;这些差异会让我们感觉非常麻烦(而且支持的平台越多越麻烦)。幸运的是Python的os模块设计者已经帮我们想到了这些问题。os模块有5个很有用的属性。它们被列在了表9.2中。
    9.3 文件内建方法 - 图8
    不管你使用的是什么平台,只要你导入了os模块,这些变量自动会被设置为正确的值,减少了你的麻烦。

    还要提醒大家的是:print语句默认在输出内容末尾后加一个换行符,而在语句后加一个逗号就可以避免这个行为。readline()和readlines()函数不对行里的空白字符做任何处理(参见本章练习),所以你有必要加上逗号。如果你省略逗号,那么显示出的文本每行后会有两个换行符,其中一个是输入是附带的,另一个是print语句自动添加的。
    文件对象还有一个truncate()方法,它接受一个可选的size作为参数。如果给定,那么文件将被截取到最多size字节处。如果没有传递size参数,那么默认将截取到文件的当前位置。例如:你刚打开了一个文件,然后立即调用truncate()方法,那么你的文件(内容)实际上被删除,这时候你其实是从0字节开始截取的(tell()将会返回这个数值)。
    在学习下一小节之前,我们再来看两个例子,第一个展示了如何输出到文件,第二个展示了文件的输出和输入,以及用于文件定位的seek()和tell()方法的使用。
    9.3 文件内建方法 - 图9
    这里我们每次从用户接收一行输入,然后将文本保存到文件中。由于raw_input()不会保留用户输入的换行符,调用write()方法时必须加上换行符。而且,在键盘上很难输入一个EOF (end-of-file)字符,所以,程序使用句点(.)作为文件结束的标志,当用户输入句点后会自动结束输入并关闭文件。
    第二个例子以可读可写模式创建一个新的文件(可能是清空了一个现有的文件).在向文件写入数据后,我们使用seek()方法在文件内部移动,使用tell()方法展示我们的移动过程。
    9.3 文件内建方法 - 图10
    9.3 文件内建方法 - 图11
    表9.3文件对象的内建方法列表。
    9.3 文件内建方法 - 图12