Python编程基础之八文件和输入输出

一、简介

      文件存储是长久保存数据很重要的方式,Python的文件处理和相关输入输出能力直接影响系统的性能,了解文件对象(包括内建函数、方法和属性)、标准文件、文件系统的访问方法、文件执行和相关的模块都是很有必要的。

二、详解

1、文件对象

        文件对象不仅可以用来访问普通的磁盘文件,而且也可以访问任何其它类型抽象层面上的"文件"。一旦设置了合适的"钩子,就可以访问具有文件类型接口的其它对象,就好像访问的是普通文件一样。
        有很多处理"类文件"对象的情况,例如实时地"打开一个 URL"来读取 Web 页面,在另一个独立的进程中执行一个命令进行通讯, 就好像是两个同时打开的文件, 一个用于读取,另个用于写入。
        内建函数open()返回一个文件对象,对该文件进行后继相关的操作都要用到它。 还有大量的函数也会返回文件对象或是类文件( file-like )对象。进行这种抽象处理的主要原因是许多的输入/输出数据结构更趋向于使用通用的接口,这样就可以在程序行为和实现上保持一致性。甚至像Unix这样的操作系统把文件作为通信的底层架构接口。 注意:文件只是连续的字节序列.,数据的传输经常会用到字节流, 无论字节流是由单个字节还是大块数据组成。

2、文件内建函数[open()和 file()]

        作为打开文件之门的"钥匙",内建函数open()[以及file()]提供了初始化输入/输出(I/O)操作的通用接口。open() 内建函数成功打开文件后时候会返回一个文件对象, 否则引发一个错误。当操作失败,Python会产生一个IOError异常。内建函数open()的基本语法是:file_object = open(file_name, access_mode='r', buffering=-1)。
        file_name是包含要打开的文件名字的字符串, 它可以是相对路径或者绝对路径。 可选变量access_mode也是一个字符串,代表文件打开的模式。 通常,文件使用模式 'r'、'w'或是'a'模式来打开,分别代表读取、写入和追加。还有个'U'模式,代表通用换行符支持。使用'r'或'U'模式打开的文件必须是已经存在的;使用'w'模式打开的文件若存在则首先清空,然后(重新)创建;以 'a' 模式打开的文件是为追加数据作准备的,所有写入的数据都将追加到文件的末尾(即使seek到了其它的地方),如果文件不存在,将被自动创建,类似以'w'模式打开文件。 如果没有给定access_mode,它将自动采用默认值'r'。
       另外一个可选参数buffering,用于指示访问文件所采用的缓冲方式。其中0表示不缓冲, 1表示只缓冲一行数据, 任何其它大于 1的值代表使用给定值作为缓冲区大小。不提供该参数或者给定负值代表使用系统默认缓冲机制,既对任何类电报机( tty )设备使用行缓冲,其它设备使用正常缓冲。一般情况下使用系统默认方式即可。
 (1)文件对象的访问模式


(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模块的相关属性。

3、文件内建方法

       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 应该是一个返回字符串的可迭代对象

4、文件内建属性

       文件对象除了方法之外,还有一些数据属性。这些属性保存了文件对象相关的附加数据, 例如文件名(file.name ),文件的打开模式( file.mode ),文件是否已被关闭( file.closed)以及一个标志变量, file.softspace决定print语句打印下一行前是否要加入一个空白字符。


5、标准文件

       三个标准文件:它们分别是标准输入(一般是键盘),标准输出(到显示器的缓冲输出)和标准错误(到屏幕的非缓冲输出)。 这里所说的"缓冲"和"非缓冲"是指open()函数的第三个参数。 这些文件沿用的是C语言中的命名,分别为stdin、stdout和stderr,这些文件已经被预先打开了,只要知道它们的文件句柄就可以随时访问这些文件。
        Python中可以通过sys模块来访问这些文件的句柄,导入sys模块以后,就可以使用sys.stdin、sys.stdout和sys.stderr访问。print语句通常是输出到sys.stdout;而内建raw_input()则通常从sys.stdin接受输入。注意,sys.* 是文件, 所以你必须自己处理好换行符。而 print 语句会自动在要输出的字符串后加上换行符。

6、命令行参数

        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。

7、文件系统

       对文件系统的访问大多通过Python的os模块实现。该模块是Python访问操作系统功能的主要接口。os 模块实际上只是真正加载的模块的前端,而真正的那个"模块"明显要依赖与具体的操作系统,不需要直接导入 那个模块,只要导入os模块, Python就会选择正确的模块,所以不需要考虑底层的工作。根据系统支持的特性,可能无法访问到一些在其它系统上可用的属性。除了对进程和进程运行环境进行管理外,os模块还负责处理大部分的文件系统操作,这些功能包括删除/重命名文件、 遍历目录树以及管理文件访问权限等。
        另一个模块os.path可以完成一些针对路径名的操作。它提供的函数可以完成管理和操作文件路径名中的各个部分,获取文件或子目录信息、文件路径查询等操作。
         os模块和os.path模块,提供了与平台和操作系统无关的统一的文件系统访问方法。os和os.path模块提供了访问计算机文件系统的不同方法,此处 只是文件访问方面事实上 os模块可以完成更多工作, 可以通过它管理进 程环境甚至可以让一个 Python 程序直接与另外一个执行中的程序"对话"
         os 模块的文件/目录访问函数:


       os.path模块中的路径名访问函数:

8、相关模块

还有大量的其它模块与文件和输入/输出有关:

       fileinput模块遍历一组输入文件,每次读取它们内容的一行,如果没有明确给定文件名, 则默认从命令行读取文件名。
       glob和fnmatch模块提供了老式Unix shell样式文件名的模式匹配,例如使用星号( * )通配符代表任意字符串,用问号( ? )匹配任意单个字符。虽然glob和fnmatch提供了Unix样式的模式匹配,但它们没有提供对波浪号(用户目录)字符~ 的支持。可以使用os.path.expanduser()函数来完成这个功能,传递一个带波浪号的目录,然后它会返回对应的绝对路径。
        gzip和zlib模块提供了对zlib压缩库直接访问的接口。gzip模块是在zlib模块上编写的,不但实现了标准的文件访问,还提供了自动的gzip压缩/解压缩。bz2类似于gzip,用于操作bzip压缩的文件。
        shutil模块提供高级的文件访问功能,包括复制文件、复制文件的访问权限、递归地目录树复制等等。
        tempfile模块用于生成临时文件(名)。
        其它的Python类文件对象还有网络和文件socket对象( socket 模块),用于管道连接的popen*()文件对象( os 和 popen2 模块),用于底层文件访问的fdopen()文件对象(os 模块),通过URL( Uniform Resource Locator 统一资源定位器)建立的到指定 web 服务器的网络连接( urllib 模块)等。需要注意的是并非所有的标准文件方法都能在这些对象上实现,同样的这些对象也提供了一些普通文件没有的功能。

三、总结

(1)os模块和os.path模块对文件的处理应用还将会作进一步总结。
(2)若有不足,请留言,在此先感谢!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌托邦2号

博文不易,支持的请给予小小打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值