![自学Python:编程基础、科学计算及数据分析](https://wfqqreader-1252317822.image.myqcloud.com/cover/254/34659254/b_34659254.jpg)
2.6 文件读写
读写文件是我们经常会遇到的问题。Python提供了一个方便的文件读写模式。
2.6.1 读文件
假设我们有一个文件“test.txt”,内容为:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/95_01.jpg?sign=1738874414-yYgUJVNGb7yr1pcEA2gMPZGps75vMY6g-0-314879d512bba5621a55e599efc7e856)
在Python中,我们可以使用open()或者file()函数来读取文件。两者都使用文件名作为参数来打开一个文件:
In [1]: f = file('test.txt')
In [2]: f = open('test.txt')
两种方式基本没有区别,Python推荐使用open()函数进行操作。
open()函数返回一个打开的文件对象:
In [3]: f
Out[3]: <open file 'test.txt', mode 'r' at 0x00000000048B6270>
其中,“r”表示只读模式。
open()函数默认以只读的方式打开文件,如果文件不存在,程序会抛出异常。只读模式(Read-Only Mode)指的是只能读取文件的内容而不能修改它。
我们可以调用.read()方法来一次读取文件中的所有内容:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/95_02.jpg?sign=1738874414-JokEawx2IcnXhPVpH3bf98XF7fFNKpzZ-0-5d78b888b0dd025a1175a86a95b8397b)
当读取完一个文件时,需要使用.close()方法将这个文件关闭:
In [5]: f.close()
刚才的.close()方法已经将文件关闭,再次读取需要重新打开该文件:
In [6]: f = open('test.txt')
也可以使用.readlines()方法对文件内容按行读取,该方法返回一个列表,每个元素为文件中每一行的内容:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/95_03.jpg?sign=1738874414-lbRjAl7xTWUft9sWE7U9v1Rn8ppbt1He-0-dad57094f4adbb0e5ac477fa24bfe86f)
返回的列表中,每一行行末的回车符“\n”会被保留。
for循环支持文件对象的迭代,每次读取一行,直到不能读取为止:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/95_04.jpg?sign=1738874414-YkrbfYcslardQJZXPAUfqAli86Cde5AR-0-06e68eb45d73d2ac2009c01a8a6a2bdd)
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/96_01.jpg?sign=1738874414-930gEP60faVoWt2zI9RiLYA1N7D9nDzf-0-ab213e6203c29861093107f49c213b9d)
还可以使用.readline()函数只读取文件的一行:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/96_02.jpg?sign=1738874414-MIEy2QDSN8fSeFn9Ae8pOo3nRYnvDIMD-0-9b55ccc0b9a1d6246f0f8bbf3815fa89)
在这种情况下,文件并没有被读取完整,我们可以继续读取后续的内容。
例如,如果我们调用.read()方法,会得到除第一行之外的所有内容:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/96_03.jpg?sign=1738874414-bYHWhEh2OvKc7veB5YXDurT1L2WluRdh-0-f27dbfbd8d282d64d64b56387433a7b6)
2.6.2 写文件
写文件同样使用open()函数,只不过我们需要改变它的文件打开方式。
open()函数默认的打开方式为只读,即“mode='r'”:
open(name, mode='r')
写文件的时候,可以将模式转化为写:
In [1]: f = open('myfile.txt', 'w')
w表示文件是只写模式(Write-Only Mode),在该模式下,如果文件不存在,这个文件会被创建出来;如果文件存在,文件中的内容将被清空。
可以使用文件对象的.write()方法向其中写入文字:
In [2]: f .write('hello world!')
文件写入完成后,和读文件一样,需要关闭这个文件:
In [3]: f .close()
我们可以通过读取这个文件的内容来验证是否已经将文字写入这个文件:
In [4]: open('myfile.txt').read()
Out[4]: 'hello world!'
如果文件已经存在,只写模式会清除之前文件的所有内容,重新开始写入,在这种情况下,文件中之前的数据是不可恢复的:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/97_01.jpg?sign=1738874414-VTG0XktseqkBNxjSELMAbEDBk5UuFo2Q-0-8937dec2dde43d7e9446555e1c23a134)
除了只读、只写模式之外,open()函数还执行其他类型的操作模式,比如以a表示的追加模式(Append Mode)。
追加模式不会覆盖原有的内容,而是从文件的结尾开始写入:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/97_02.jpg?sign=1738874414-CTdHBrt5iT9xjUDmzMlnMitXiI9nCijY-0-8689ef764fdc74302dd42e93f795260e)
处于只读或者追加模式的文件对象不能同时进行读取操作,而处于只读模式的文件不能同时进行写入操作。我们可以使用“w+”表示的读写模式实现同时读取和写入文件。读写模式仍然会清除之前已有的内容,不过增加了读取当前写入的内容的功能:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/97_03.jpg?sign=1738874414-mf41y55zpAMj9NIDJboC6AHXBs2mo07j-0-430e05e092a07f616838e03b4a35b1c0)
打开文件之后,需要使用.close()方法关闭这个文件。在Python中,当一个文件对象不再被其他变量引用时,Python会自动调用.close()方法关闭这个文件。因此,大多数情况下,即使我们忘记调用文件的.close()方法,文件最终还是会被正常关闭。
不过在少数情况下,如果我们在写文件时没有关闭文件,可能会遇到文件没有及时写入的问题:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/97_04.jpg?sign=1738874414-qIXbLjcv1TaDbrGKuk7m1TVyhf1oWWo8-0-da787e5716ebb488e87e9a892a3e875f)
虽然写入了“hello world”,但是在文件关闭之前,这个内容并没有被完全写入磁盘。
2.6.3 中文文件的读写
在学习字符串的时候注意到,中文字符的字符串表示和Unicode字符串表示是不同的:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/98_01.jpg?sign=1738874414-JHTegc4ZkotgEalO8e35gFFVL0W9NlBN-0-5f2427436b5604960caaf75f0f937a4a)
从字符长度的角度来看,Unicode字符串的表示更符合我们的日常认知,所以我们一般使用Unicode字符串处理中文文件。
1. 写中文文件
open()函数是按照ASCII码字符串的形式来读写中文文件的,直接写Unicode字符串会抛出异常:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/98_02.jpg?sign=1738874414-oPOUzRJe07AZByuxYJ8pNbgdsNbWZRRG-0-c35cf36fa7a716cf39e0ffe24a9e99b4)
如果要写入Unicode字符串b,我们需要用调用它的.encode()方法将其转化为普通字符串:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/98_03.jpg?sign=1738874414-Rgymhs91whLRnWklo8IO6no9ZlflNHFm-0-b04807a2d7ec97fb9e4cf33862d74e49)
这样做不是很方便,好在Python提供了codecs模块来读写不同格式的字符串。
首先导入该模块:
In [11]: import codecs
我们可以使用codecs.open()函数实现Unicode字符串的写入,只需要在打开文件时,通过encoding参数指定文件的编码格式:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/98_04.jpg?sign=1738874414-L4djByB8dS9G2F8Pa6wKzGqq85kIld7X-0-b028201a638e690d4a53c87c6de74d3c)
2. 读中文文件
接下来,我们再看open()函数与codecs.open()函数在读中文文件时的差异。
open()函数只能将中文读成普通字符串:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/99_01.jpg?sign=1738874414-4WV0JMkmMKkLBxogj9c14KAZtAG5wVTr-0-ce930aa2152271eaef17b61a210f3315)
codecs.open()函数则可以通过指定参数将中文读取成Unicode字符串:
![](https://epubservercos.yuewen.com/9B8D30/18513172808564606/epubprivate/OEBPS/Images/99_02.jpg?sign=1738874414-1oh54sj5Xo9gbfZpB5sPDuJCEba7mzlZ-0-133f0bfc48d6ef28776f0986689a3950)
因此,在处理中文文件时,我们通常使用codecs.open()函数代替open()函数。