6.4.2 文件操作

最后更新于:2022-04-02 00:29:32

### 6.4.2 文件操作 常用计算机的人都知道,许多应用软件(如 Word、媒体播放器等)都需要处理文件, 并且都需要经过打开文件、读写文件、关闭文件的步骤,这其实是程序设计中文件处理的一 般过程的反映。 打开文件 在读写文件之前首先需要“打开”文件,这个步骤可以简单地理解为对磁盘文件进行必 要的初始化,至于其底层细节则无需了解。 Python 提供了函数 open 用于文件打开,用法如下: ``` f = open(<文件名>,<打开方式>) ``` 其含义是按指定的<打开方式>打开由<文件名>标识的磁盘文件,创建一个文件对象作为函 数的返回值,并使变量 f 引用这个文件对象。常用的打开方式包括"r"和"w",它们分别表示 “读”方式和“写”方式。 顺便强调一下,Python 中的文件处理是面向对象风格的,即文件是一个对象,通过文 件对象的方法来实现文件操作。我们在第 5 章中初步介绍了对象概念,并且将在第 7 章详细 讨论面向对象。 为了读取一个文件的内容,需要以读方式打开文件。例如: ``` f = open("oldfile.dat","r") ``` 成功执行后,就可以通过文件对象 f 来读取文件 oldfile.dat 的内容了。若指定的文件不存在, 则 Python 将报错(IOError)。 为了向一个文件中写入内容,需要以写方式打开文件。例如: ``` f = open("newfile.txt","w") ``` 成功执行后,就可以通过文件对象 f 来向文件 oldfile.dat 中写入内容了。注意,以写方式打 开文件时,如果指定的文件不存在,则创建该文件;如果指定的文件已经存在,则会清除该 文件原来的内容,即相当于创建新文件。所以,以写方式打开文件时一定要小心,不要把现 有文件破坏了。 读文件 在介绍文件读写之前,先要理解文件“当前读写位置”的概念。读者应该了解老式的录 放机的录放过程吧:录放机有一个磁头,用于读取或录入磁带信息,随着磁带的转动,磁头 也就不断改变着录放位置。Python 中的文件采用类似的顺序读写过程:打开文件后,当前 读写位置就是文件开始处;随着读写命令的执行,当前读写位置不断改变,直至到达文件末 尾。 Python 中的文件对象提供了 read()、readline()和 readlines()方法用于读取文件内容。 read()的用法如下: ``` <变量> = <文件对象>.read() ``` 含义是读取从当前位置直到文件末尾的内容,并作为字符串返回。如果是刚打开的文件对象, 则返回的字符串包含文件的所有内容。 read()方法也可以带有参数: ``` <变量> = <文件对象>.read(n) ``` 含义是读取从当前位置开始的 n 个字符,并以此字符串作为返回值。如果指定的 n 大于文件中从当前位置到末尾的字符数,则仅返回这些字符。如果当前位置已到达文件末尾,则 read 返回空串。 假设有一个文件 rhyme.txt,其文本内容是: ``` Good, better, best, Never let it rest, Till good is better, And better, best. ``` 下面的语句序列对此文件进行读取 ``` >>> f = open("rhyme.txt","r") >>> s = f.read(8) >>> s 'Good, be' >>> f.read(20) 'tter, best,\nNever le' >>> print f.read() t it rest, Till good is better, And better, best. >>> f.close() ``` readline()的用法如下: ``` <变量> = <文件对象>.readline() ``` 含义是读取从当前位置到行末(即下一个换行字符)的所有字符,并以此字符串作为返回值, 赋值给变量。通常用此方法来读取文件的当前行。如果当前处于文件末尾,则 readline 返回 空串。例如: ``` >>> f = open("rhyme.txt","r") >>> s = f.readline() >>> s 'Good, better, best,\n' >>> f.readline() 'Never let it rest,\n' >>> print f.readline() Till good is better, >>> f.close() ``` readlines()的用法如下: ``` <变量> = <文件对象>.readlines() ``` 其含义是读取从当前位置直到文件末尾的所有行,并将这些行构成一个字符串列表作为返回 值,列表中的每个元素都是文件的一行。如果当前处于文件末尾,则 readlines 返回空列表。 例如: ``` >>> f = open("rhyme.txt","r") >>> f.readline() 'Good, better, best,\n' >>> f.readline() 'Never let it rest,\n' >>> f.readlines() ['Till good is better,\n', 'And better, best.\n'] >>> f.readlines() [] ``` 写文件 当文件以写方式打开时,可以向文件中写入文本内容。与读文件一样,写入位置也是由 “当前读写位置”决定的。Python 文件对象提供两种写文件的方法: ``` <文件对象>.write(<字符串>) <文件对象>.writelines(<字符串列表>) ``` 其中,write 的含义是在文件当前位置处写入字符串,writelines 的含义是在文件当前位置处依次写入列表中的所有字符串。 下面的语句序列创建了一个新文件,并向其中写入了李白的名诗: ``` >>> f = open("d:/libai.txt","w") >>> f.write("窗前明月光") >>> f.write("疑是地上霜\n") >>> f.write("举头望明月\n 低头思故乡") >>> f.close() ``` 注意每一次 f.write()都是紧接着上次写入的内容继续的,并不会因为是另一条 f.write()就另 起一行。为了写多行文本,必须人工添加换行字符“\n”。那么,上述语句序列所创建的文 件 libai.txt 有几行文本呢?没错,只有 3 行,因为第一次调用 f.write 时并没有写入换行符, 这导致诗的前两句被写在同一行上了。如图 6.2 所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-22_56cafce274d38.png) 图 6.2 写入多行文本 再次强调,写方式打开文件会导致要么创建一个新文件,要么清除一个旧文件,总之文件的内容是全新的。那么有没有办法在现有文件内容基础上再写入一些新内容呢?答案是肯 定的。Python 还提供一种文件打开方式"a",表示“追加”。以追加方式打开文件后,当前位 置被定位在文件末尾,可以继续写入文本而不改变原有的文件内容。例如: ``` >>> f = open("d:/libai.txt","a") >>> f.write("\n---- 李白《静夜思》") >>> f.close() ``` 结果如图 6.3 所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-22_56cafce28978b.png) 图 6.3 向文件追加写入内容 关闭文件 文件处理结束后需要关闭文件,这个步骤大体上涉及释放分配给文件的系统资源,以便 分配给其他文件使用。通过调用文件对象的 close 方法来关闭文件: ``` <文件对象>.close() ``` 注意,即使程序中没有关闭文件,Python 程序结束时也会自动关闭所有打开的文件。 然而好的做法是由程序自己关闭文件,否则有可能因程序意外终止而导致文件数据丢失。例 如,以写方式打开文件时,如果向文件中写入了文本但还没有关闭文件,那么所写内容是不 会存盘的。这时再以读方式打开同一文件,read()命令返回的是空串。下面的语句序列演示 了这种情况。 ``` >>> f = open("d:/test","w") >>> f.write("some words") >>> g = open("d:/test","r") >>> g.read() '' >>> f.close() >>> g.seek(0) >>> g.read() 'some words' ``` 所以,强烈建议读者在程序中一旦结束对文件的读写,就立即关闭文件。 文件处理程序的常见结构 许多应用程序的算法结构都属于直接了当的 IPO(输入-处理-输出)模式,当输入输 出都是文件时,程序的结构大体如下: ``` infile = open("input.dat","r") outfile = open("output.dat","w") while True: text = infile.readline() if text == "": break do something with text ... outfile.write(data) infile.close() outfile.close() ``` 此代码的核心是一个 while 循环,循环的每一步利用 readline()读取输入文件的一行,然后对该行进行处理,并将处理结果写入输出文件。当某次循环读到空行(视为文件尾),则利用 break 跳出循环体,从而结束对文件的处理。 除了“while 循环+readline()”的结构,还可以利用“for 循环+readlines()”的结构。readlines() 一次性读出所有行,形成一个列表,然后针对这个列表进行循环。 ``` for line in infile.readlines(): do something with line ... ``` 实际上,Python 语言甚至允许直接将打开的文件与 for 循环结合使用,达到和“for 循 环+readlines()”同样的效果。代码如下: ``` infile = open("input.dat","r") for line in infile: do something with line ... ``` 这种用法有个好处是无需考虑内存大小,而 readlines()要求内存足够大,以便容纳它返回的 列表。 向文件追加数据 前述读方式打开的文件只能读取不能写入,写方式打开的文件是新建文件(写打开现存文件的话将清除内容),只能写入不能读取。有没有办法保留现存文件的内容并加入新内容 呢? 一种做法是先将文件的现有数据利用 readlines()读出来存入一个列表,然后向该列表添 加数据,最后再把新列表写入文件。这种做法对小文件没有问题,但当文件大小为数百 MB 或若干 GB 时,为了保存所有行的列表需要消耗大量内存。 其实 Python 还提供了一种打开方式"a",称为“追加”方式,可以用于在现存文件的尾 部追加新数据。当然,如果请求打开的文件不存在,"a"方式就和"w"方式一样,创建一个新 文件。下面的语句演示了追加方式的用法: ``` >>> f = open("oldfile.txt","a") >>> f.write("something new\n") >>> f.close() ```
';