文件存储是长久保存数据很重要的方式,Python的文件处理和相关输入输出能力直接影响系统的性能,了解文件对象(包括内建函数、方法和属性)、标准文件、文件系统的访问方法、文件执行和相关的模块都是很有必要的。
文件对象不仅可以用来访问普通的磁盘文件,而且也可以访问任何其它类型抽象层面上的"文件"。一旦设置了合适的"钩子,就可以访问具有文件类型接口的其它对象,就好像访问的是普通文件一样。
有很多处理"类文件"对象的情况,例如实时地"打开一个 URL"来读取 Web 页面,在另一个独立的进程中执行一个命令进行通讯, 就好像是两个同时打开的文件, 一个用于读取,另个用于写入。
内建函数open()返回一个文件对象,对该文件进行后继相关的操作都要用到它。 还有大量的函数也会返回文件对象或是类文件( file-like )对象。进行这种抽象处理的主要原因是许多的输入/输出数据结构更趋向于使用通用的接口,这样就可以在程序行为和实现上保持一致性。甚至像Unix这样的操作系统把文件作为通信的底层架构接口。 注意:文件只是连续的字节序列.,数据的传输经常会用到字节流, 无论字节流是由单个字节还是大块数据组成。
(2)工厂函数 file()
在Python 2.2中,类型和类被统一了起来,这时加入了内建函数file()。当时,很多的内建类型没有对应的内建函数来创建对象的实例。例如dict()、bool()、file()等等。然而,另一些却有对应的内建函数,例如list()、str()等等。open()和file()函数具有相同的功能,可以任意替换。在将来的Python版本中,open()和file()函数会同时存在,完成相同的功能。一般说来,建议使用open()来读写文件。
(3)通用换行符支持(UNS)
不同平台用来表示行结束的符号是不同的,例如 \n, \r, 或者\r\n,Python的解释要用相同的方式处理所有文件,即引入了UNS,使用'U'标志打开文件的时候,所有的行分割符(或行结束符)通过Python的输入方法(例如read*() )返回时都会被替换为换行符 NEWLINE(\n)('rU' 模式也支持 'rb' 选项) 。 这个特性还支持包含不同类型行结束符的文件,文件对象的newlines属性会记录它曾
“看到的”文件的行结束符。
如果文件刚被打开,程序还没有遇到行结束符,那么文件的newlines为None。在第一行被读取后,它被设置为第一行的结束符。如果遇到其它类型的行结束符,文件的newlines会成为一个包含每种格式的元组。注意UNS只用于读取文本文件,没有对应的处理文件输出的方法。
在编译Python的时候,UNS默认是打开的。如果你不需要这个特性,在运行configure脚本时,可以使用--without-universal-newlines开关关闭它。如果你非要自己处理行结束符,请查阅核心笔记,使用os模块的相关属性。
open()成功执行并返回一个文件对象之后,所有对该文件的后续操作都将通过这个"句柄"进行。文件方法可以分为四类:输入、 输出、文件内移动以及杂项操作。
(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 infile代替它。另个废弃的方法是readinto() ,它读取给定数目的字节到一个可写的缓冲器对象,和废弃的buffer()内建函数返回的对象是同个类型(由于buffer()已经不再支持,所以readinto()被废弃)。
(2)输出
write()内建方法功能与read()和readline()相反。它把含有文本数据或二进制数据块的字符串写入到文件中去。和readlines()一样,writelines()方法是针对列表的操作,它接受一个字符串列表作为参数,将它们写入文件。 行结束符并不会被自动加入,所以如果需要的话,必须在调用writelines()前给每行结尾加上行结束符。
注意:这里并没有 "writeline()" 方法,因为它等价于使用以行结束符结尾的单行字符串调用write()方法。
注意:当使用输入方法如 read() 或者 readlines()从文件中读取行时,Python并不会删除行结束符,这个操作被留给了程序员。例如这样的代码在 Python 程序中很常见:
f = open('myFile', 'r')
data = [line.strip() for line in f.readlines()]
f.close()
类似地,输出方法write()或writelines()也不会自动加入行结束符,应该在向文件写入数据前自己完成。
(3)文件内移动
seek()方法(类似C中的fseek()函数)可以在文件中移动文件指针到不同的位置。offset字节代表相对于某个位置偏移量,位置的默认值为0,代表从文件开头算起(即绝对偏移量),1代表从当前位置算起, 2代表从文件末尾算起。fseek() 中0, 1, 2分别对应着常量SEEK_SET, SEEK_CUR以及SEEK_END。当打开文件进行读写操作的时候就会接触到seek()方法。
text() 方法是对seek()的补充,它告诉当前文件指针在文件中的位置(从文件起始算起),单位为字节。
(4)文件迭代
一行一行访问文件很简单:for eachLine in f:,在这个循环里,eachLine代表文本文件的一行(包括末尾的行结束符),可以使用它做任何想做的事情。
在Python 2.2之前,从文件中读取行的最好办法是使用file.readlines()来读取所有数据,这样可以尽快释放文件资源。如果不需要这样做,那么可以调用file.readline()一次读取一行。曾有一段很短的时间,file.xreadlines()是读取文件最高效的方法。而在Python 2.2中,引进了迭代器和文件迭代,这使得一切变得完全不同,文件对象成为了它们自己的迭代器。这意味着用户不必调用read*()方法就可以在for循环中迭代文件的每一行。另外也可以使用迭代器的next方法, file.next()可以用来读取文件的下一行。和其它迭代器一样,Python也会在所有行迭代完成后引发StopIteration异常,文件迭代更为高效。
(5)文件方法杂项
close()通过关闭文件来结束对它的访问。Python垃圾收集机制也会在文件对象的引用计数降至零的时候自动关闭文件。这在文件只有一个引用时发生,例如fp = open(...),然后 fp在原文件显式地关闭前被赋了另一个文件对象。良好的编程习惯要求在重新赋另个文件对象前关闭这个文件,如果不显式地关闭文件,那么可能丢失输出缓冲区的数据。
fileno()方法返回打开文件的描述符,这是一个整数,可以用在如os模块(os.read())的一些底层操作上。
调用flush()方法会直接把内部缓冲区中的数据立刻写入文件,而不是被动地等待输出缓冲区被写入。isatty()是一个布尔内建函数,当文件是一个类tty设备时返回True,否则返回False。
行分隔符和其它文件系统的差异,不同的操作系统所支持的行分隔符和路径分隔符都不同,当要跨平台的应用的时候,这些差异会让我们感觉非常麻烦(而且支持的平台越多越麻烦)。幸运的是Python的os模块设计者已经帮我们想到了这些问题。os模块有五个很有用的属性。
os 模块属性 描述
linesep 用于在文件中分隔行的字符串
sep 用来分隔文件路径名的字符串
pathsep 用于分隔文件路径的字符串
curdir 当前工作目录的字符串名称
pardir (当前工作目录的)父目录字符串名称
print语句默认在输出内容末尾后加一个换行符, 而在语句后加一个逗号就可以避免这个行为。readline()和readlines()函数不对行里的空白字符做任何处理,所以有必要加上逗号,如果省略逗号,那么显示出的文本每行后会有两个换行符,其中一个是输入是附带的,另个是print语句自动添加的。
>>> print 'aaaa',;print 'bbbb'
aaaa bbbb
文件对象还有一个truncate()方法,它接受一个可选的size作为参数。如果给定, 那么文件将被截取到最多size字节处。 如果没有传递size参数,那么默认将截取到文件的当前位置。例如,刚打开了一个文件,然后立即调用truncate()方法, 那么文件(内容)实际上被删除,这时候其实是从0字节开始截取的( tell() 将会返回这个数值 )。
文件对象的方法 操作
file.close() 关闭文件
file.fileno() 返回文件的描述符(file descriptor ,FD, 整数值)
file.flush() 刷新文件的内部缓冲区
file.isatty() 判断 file 是否是一个类tty设备
file.next() 返回文件的下一行(类似于 file.readline() ), 或在没有其它行时引发StopIteration异常
file.read(size=-1) 从文件读取 size 个字节, 当未给定 size 或给定负值的时候, 读取剩余的所有字节, 然后作为字符串返回
file.readinto(buf, size) 从文件读取 size 个字节到 buf 缓冲器(已不支持)
file.readline(size=-1) 从文件中读取并返回一行(包括行结束符), 或返回最大size个字符
file.readlines(sizhint=0) 读取文件的所有行并作为一个列表返回(包含所有的行结束符)
file.xreadlines () 用于迭代, 可以替换 readlines() 的一个更高效的方法
file.seek(off, whence=0) 在文件中移动文件指针, 从whence偏移off字节
file.tell() 返回当前在文件中的位置
file.truncate(size=file.tell()) 截取文件到最大size字节, 默认为当前文件位置
file.write(str) 向文件写入字符串
file.writelines(seq) 向文件写入字符串序列 seq ; seq 应该是一个返回字符串的可迭代对象
sys模块通过sys.argv属性提供了对命令行参数的访问。 命令行参数是调用某个程序时除程序名以外的其它参数。
熟悉C语言的读者可能会问了,"argc 哪去了?" argc和argv分别代表参数个数(argument count)和参数向量(argument vector)。argv变量代表一个从命令行上输入的各个参数组成的字符串数组, argc变量代表输入的参数个数。在Python中,argc其实就是sys.argv列表的长度,而该列表的第一项sys.argv[0]永远是程序的名称。总结:一、sys.argv是命令行参数的列表。二、len(sys.argv)是命令行参数的个数(即argc)。
命令行参数有用吗? Unix操作系统中的命令通常会接受输入,执行一些功能,然后把结果作为流输出出来。 这些输出的结果还可能被作为下一个程序的输入数据,在完成了一些其它处理后,再把新的输出送到下一个程序,如此延伸下去。各个程序的输出一般是不保存的,这样可以节省大量的磁盘空间,各个程序的输出通常使用"管道"实现到下个程序输入的转换。
Python还提供了两个模块用来辅助处理命令行参数。其中一个最原始的是getopt模块,它更简单些,但不是很精细。而Python 2.3引入的optparse模块提供了一个更强大的工具,而且它更面向对象。如果用到一些简单的选项推荐getopt ,但如果你需要提供复杂的选项使用optparse。