利用Python中的输入和输出功能进行读取和写入的教程
读取、写入和Python
编写程序的最后一个基本步骤就是从文件读取数据和把数据写入文件。阅读完这篇文章之后,可以在自己的to-do列表中加上检验这个技能学习效果的任务。
简单输出
贯穿整个系列,一直用print语句写入(输出)数据,它默认把表达式作为string写到屏幕上(或控制台窗口上)。清单1演示了这一点。清单1重复了第一个Python程序“Hello,World!”,但是做了一些小的调整。
清单1.简单输出
>>>print"HelloWorld!" HelloWorld! >>>print"Thetotalvalueis=$",40.0*45.50 Thetotalvalueis=$1820.0 >>>print"Thetotalvalue=$%6.2f"%(40.0*45.50) Thetotalvalue=$1820.00 >>>myfile=file("testit.txt",'w') >>>print>>myfile,"HelloWorld!" >>>print>>myfile,"Thetotalvalue=$%6.2f"%(40.0*45.50) >>>myfile.close()
正如这个示例演示的,用print语句写入数据很容易。首先,示例输出一个简单的string。然后创建并输出复合的string,这个字符串是用string格式化技术创建的。
但是,在这之后,事情发生了变化,与代码以前的版本不同。接下来的一行创建file对象,传递进名称"testit.txt"和'w'字符(写入文件)。然后使用修改过的print语句——两个大于号后边跟着容纳file对象的变量——写入相同的string。但是这一次,数据不是在屏幕上显示。很自然的问题是:数据去哪儿了?而且,这个file对象是什么?
第一个问题很容易回答。请查找testit.txt文件,并像下面那样显示它的内容。
%moretestit.txt HelloWorld! Thetotalvalue=$1820.00
可以看到,数据被准确地写入文件,就像以前写到屏幕上一样。
现在,请注意清单1中的最后一行,它调用file对象的close方法。在Python程序中这很重要,因为在默认情况下,文件输入和输出是缓冲的;在调用print语句时,数据实际未被写入;相反,数据是成批写入的。让Python把数据写入文件的最简单方式就是显式地调用close方法。
文件对象
file是与计算机上的文件进行交互的基本机制。可以用file对象读取数据、写入数据或把数据添加到文件,以及处理二进制或文本数据。
学习file对象的最简单方法就是阅读帮助,如清单2所示。
清单2.得到file对象的帮助
>>>help(file) Helponclassfileinmodule__builtin__: classfile(object) |file(name[,mode[,buffering]])->fileobject | |Openafile.Themodecanbe'r','w'or'a'forreading(default), |writingorappending.Thefilewillbecreatedifitdoesn'texist |whenopenedforwritingorappending;itwillbetruncatedwhen |openedforwriting.Adda'b'tothemodeforbinaryfiles. |Adda'+'tothemodetoallowsimultaneousreadingandwriting. |Ifthebufferingargumentisgiven,0meansunbuffered,1meansline |buffered,andlargernumbersspecifythebuffersize. |Adda'U'tomodetoopenthefileforinputwithuniversalnewline |support.Anylineendingintheinputfilewillbeseenasa'\n' |inPython.Also,afilesoopenedgainstheattribute'newlines'; |thevalueforthisattributeisoneofNone(nonewlinereadyet), |'\r','\n','\r\n'oratuplecontainingallthenewlinetypesseen. | |'U'cannotbecombinedwith'w'or'+'mode. | |Note:open()isanaliasforfile(). | |Methodsdefinedhere: ...
正如帮助工具指出的,使用file对象很简单。用file构造函数或open方法创建file对象,open是file构造函数的别名。第二个参数是可选的,它指定文件的使用方式:
- 'r'(默认值)表示从文件读取数据。
- 'w'表示要向文件写入数据,并截断以前的内容。
- 'a'表示要向文件写入数据,但是添加到当前内容尾部。
- 'r+'表示对文件进行读写操作(删除以前的所有数据)。
- 'r+a'表示对文件进行读写操作(添加到当前内容尾部)。
- 'b'表示要读写二进制数据。
这篇文章的第一个代码清单向文件写入数据。现在,清单3显示如何把这个数据读入Python程序,并解析文件的内容。
清单3.从文件读取数据
>>>myfile=open("testit.txt") >>>myfile.read() 'HelloWorld!\nThetotalvalue=$1820.00\n' >>>str=myfile.read() >>>printstr >>>myfile.seek(0) >>>str=myfile.read() >>>printstr HelloWorld! Thetotalvalue=$1820.00 >>>str.split() ['Hello','World!','The','total','value','=','$1820.00'] >>>str.split('\n') ['HelloWorld!','Thetotalvalue=$1820.00',''] >>>forlineinstr.split('\n'): ...printline ... HelloWorld! Thetotalvalue=$1820.00 >>>myfile.close()
要读取数据,首先要创建合适的file对象——在这个示例中,文件对象打开testit.txt文件,并用read方法读取内容。这个方法把整个文件读入一个string,然后在程序中把这个字符串输出到控制台。在对read方法的第二个调用中,试图把值分配给str变量,结果返回一个空的string。这是因为第一个read操作读入了整个文件。当试图再次读取内容时,已经到了文件末尾,所以什么也读不到。
这个问题的解决方案也很简单:让file对象返回文件的开头。回到开头要通过seek方法进行,它接受一个参数,表示要从文件中的什么位置开始读取或写入(例如,0代表文件开头)。seek方法支持更复杂的操作,但是可能会有危险。对于目前来说,我们还坚持采用简单方式。
现在回到了文件的开始之处,可以把文件内容读入string变量并对string做适当地解析。请注意,在文件中,行之间用新行(或行结束)字符区分。如果试着在string上调用split方法,它会在空白字符(例如空格)处进行拆分。为了让方法根据新行字符拆分各行,必须显式地指定新行字符。然后可以拆分string并在for循环中对文件的行进行迭代。
看起来仅仅从文件中读取和处理一行内容都有许多工作要做。Python要让简单的事情变容易,所以您可能想知道这个任务有没有快捷方式可用。如清单4所示,答案是yes。
清单4.读取和解析行
>>>myfile=open("testit.txt") >>>forlineinmyfile.readlines(): ...printline ... HelloWorld! Thetotalvalue=$1820.00 >>>myfile.close() >>>forlineinopen("testit.txt").readlines(): ...printline ... HelloWorld! Thetotalvalue=$1820.00 >>>forlineinopen("testit.txt"): ...printline ... HelloWorld! Thetotalvalue=$1820.00
清单4演示了读取和解析文本文件行的三种技术。首先,打开文件并把它分配给变量。然后调用readlines方法,把整个文件读入内存并把内容拆分成string列表。for循环在string列表上进行迭代,一次输出一行。
第二个for循环通过使用file对象的隐式变量(也就是说,变量不是显式创建的),对这个过程稍做了点儿简化。打开文件和读取文件内容一次完成,生成的效果与第一个显式示例相同。最后一个示例进一步做了简化,并演示了直接在file对象上进行迭代的能力(请注意,这是Python的一个新特性,所以在您的计算机上可能无法工作)。在这个示例中,创建隐式file对象,然后Python做余下的工作,允许对文件中的全部行进行迭代。
但是,有些时候,在从文件读取数据时,可能想要更好的控制级别。在这种情况下,应当使用readline方法,如清单5所示。
清单5.读取数据
>>>myfile=open("testit.txt") >>>myfile.readline() 'HelloWorld!\n' >>>myfile.readline() 'Thetotalvalue=$1820.00\n' >>>myfile.readline() '' >>>myfile.seek(0) >>>myfile.readline() 'HelloWorld!\n' >>>myfile.tell() 13L >>>myfile.readline() 'Thetotalvalue=$1820.00\n' >>>myfile.tell() 40L >>>myfile.readline() '' >>>myfile.tell() 40L >>>myfile.seek(0) >>>myfile.read(17) 'HelloWorld!\nThe' >>>myfile.seek(0) >>>myfile.readlines(23) ['HelloWorld!\n','Thetotalvalue=$1820.00\n'] >>>myfile.close()
这个示例演示了如何在文件中移动,一次读取一行,或者显式地用seek方法移动文件位置指示器。首先,用readline方法在文件行中移动。当到达文件末尾时,readline方法返回一个空的string。在过了文件末尾之后,如果还用这种方式继续读取,并不会造成错误,只会返回空的string。
然后返回文件开始的地方,并读取另一行。tell方法显示出在文件中的当前位置(应当在第一行文本之后)——在这个示例中,在第13个字符位置。通过使用这个知识,可以向read或readline方法传递一个参数,控制读取的字符数。对于read方法,这个参数(在这个示例中是17)是要从文件中读取的字符数。但是readline方法在读入指定数量的字符后,还会继续读取,直到行尾。在这个示例中,它读取第一行和第二行文本。
写入数据
迄今为止的示例都侧重于读取数据,而不是写入数据。但是如清单6所示,一旦了解了使用file对象的基础知识,写入也很容易。
清单6.写入数据
>>>mydata=['HelloWorld!','Thetotalvalue=$1820.00'] >>>myfile=open('testit.txt','w') >>>forlineinmydata: ...myfile.write(line+'\n') ... >>>myfile.close() >>>myfile=open("testit.txt") >>>myfile.read() 'HelloWorld!\nThetotalvalue=$1820.00\n' >>>myfile.close() >>>myfile=open("testit.txt","r+") >>>forlineinmydata: ...myfile.write(line+'\n') ... >>>myfile.seek(0) >>>myfile.read() 'HelloWorld!\nThetotalvalue=$1820.00\n' >>>myfile.close() >>>myfile=open("testit.txt","r+a") >>>myfile.read() 'HelloWorld!\nThetotalvalue=$1820.00\n' >>>forlineinmydata: ...myfile.write(line+'\n') ... >>>myfile.seek(0) >>>myfile.read() 'HelloWorld!\nThetotalvalue=$1820.00\nHelloWorld!\nThetotalvalue=$1820.00\n' >>>myfile.close()
要把数据写入文件,必须先创建file对象。但是,在这情况下,必须用'w'模式标记指定要写入文件。在这个示例中,把mydatalist的内容写入文件,关闭文件,然后重新打开文件,这样就可以读取内容了。
但是,通常情况下,想要同时读取文件和写入文件,所以这个示例的下一部分用'r+'模式重新打开文件。因为能够写入文件,而不是添加,所以文件会被截断。首先,把mydatalist的内容写入文件,然后把文件指针重新定位到文件开头,并读入内容。然后这个示例关闭文件,并用读取和添加模式"r+a"重新打开文件。正如示例代码所示,文件内容现在是两个写入操作的结果(文本是重复的)。
处理二进制数据
前面所有的示例都处理文本数据或字符数据:写入和读取字符string。但是,在某些情况下,例如在处理整数或压缩文件时,需要能够读取和写入二进制数据。在创建file对象时,通过把'b'添加到文件模式中,可以很容易地用Python处理二进制数据,如清单7所示。
清单7.处理二进制数据
>>>myfile=open("testit.txt","wb") >>>forcinrange(50,70): ...myfile.write(chr(c)) ... >>>myfile.close() >>>myfile=open("testit.txt") >>>myfile.read() '23456789:;<=>?@ABCDE' >>>myfile.close()
在这个示例中,创建一个合适的file对象,然后用从50到69的ASCII值写入二进制字符。使用chr方法,把range方法调用创建的整数转变成字符。在写完所有数据之后,关闭文件并重新打开文件进行读取,还是使用二进制模式标记。读取文件可以证明没有把整数写入文件,相反,写的是字符值。
在读取和写入二进制数据时,必须小心,因为不同的平台用不同的方式保存二进制数据。如果必须处理二进制数据,最好是使用来自Python库的合适对象(或者来自第三方开发人员的对象)。
读取和写入:最有趣的地方
这篇文章讨论了在Python程序中如何从文件读取数据和写入数据到文件中。总体来说,过程很简单:创建合适的file对象,然后按照需要读取和写入。但是,在使用写入模式创建file文件,向文件写入数据时,必须注意文件的截断。如果需要向文件中添加数据,应当在创建file对象时,使用添加模式。