10.1 从文件中读取数据
文本文件可存储的数据量多得难以置信:天气数据、交通数据、社会经济数据、文学作品等。
每当需要分析或修改存储在文件中的信息时,读取文件都很有用,对数据分析应用程序来说尤其
如此。
要使用文本文件中的信息,首先需要将信息读取到内存中。为此,你可以一次性读取文件的
全部内容,也可以以每次一行的方式逐步读取。
10.1.1 读取整个文件
下面的程序打开并读取这个文件,再将其内容显示到屏幕上:
要以任何方式使用文件——哪怕仅仅是打印其内容,都得先打开文件,这样才能访问它。
关键字with在不再需要访问文件后将其关闭 .你也可以调用open()和close()来打开和关闭文件,但这样做时,如果程序存在bug,导致close()语句未执行,文件将不会关闭。 使用with……as……可让Python去确定:你只管打开文件,并在需要时使用它, Python自会在合适的时候自动将其关闭。
10.1.2 文件路径
当你将类似pi_digits.txt这样的简单文件名传递给函数open()时, Python将在当前执行的文件
(即.py程序文件)所在的目录中查找文件。
要让Python打开不与程序文件位于同一个目录中的文件,需要提供文件路径,它让Python到系统的特定位置去查找。
相对文件路径让Python到指定的位置去查找,而该位置是相对于当前运行的程序所在目录的。
你还可以将文件在计算机中的准确位置告诉Python,这样就不用关心当前运行的程序存储在
什么地方了。这称为绝对文件路径。在相对路径行不通时,可使用绝对路径。
通过使用绝对路径,可读取系统任何地方的文件。就目前而言,最简单的做法是,要么将数
据文件存储在程序文件所在的目录,要么将其存储在程序文件所在目录下的一个文件夹(如text_files)中。
10.1.3 逐行读取
读取文件时,常常需要检查其中的每一行:你可能要在文件中查找特定的信息,或者要以
某种方式修改文件中的文本。
要以每次一行的方式检查文件,可对文件对象使用for循环:
10.1.4 创建一个包含文件各行内容的列表 使用关键字with时, open()返回的文件对象只在with代码块内可用。如果要在with代码块外
访问文件的内容,可在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该
列表:你可以立即处理文件的各个部分,也可推迟到程序后面再处理。
10.1.5 使用文件的内容
将文件读取到内存中后,就可以以任何方式使用这些数据了。
我们将创建一个字符串,它包含文件中存储的所有数字,且没有任何空格:
读取文本文件时, Python将其中的所有文本都解读为字符串。如果你读取的是数字,并
要将其作为数值使用,就必须使用函数int()将其转换为整数,或使用函数float()将其转
换为浮点数。
10.2 写入文件
10.2.1 写入空文件
要将文本写入文件,在调用open()时需要提供另一个实参,告诉Python你要写入打开的文
件。
调用open()时提供了两个实参(见Ø)。第一个实参也是要打开的文件的名称;
第二个实参( 'w')告诉Python,我们要以写入模式打开这个文件。打开文件时,可指定读取模
式( 'r')、 写入模式( 'w')、 附加模式( 'a')或让你能够读取和写入文件的模式( 'r+')。如果
你省略了模式实参, Python将以默认的只读模式打开文件。
如果你要写入的文件不存在,函数open()将自动创建它。然而,以写入( 'w')模式打开文
件时千万要小心,因为如果指定的文件已经存在, Python将在返回文件对象前清空该文件。
使用文件对象的方法write()将一个字符串写入文件。
如果你打开文件programming.txt,将看到其中包含如下一行内容:
10.2.2 写入多行
函数write()不会在你写入的文本末尾添加换行符,因此如果你写入多行时没有指定换行符,
文件看起来可能不是你希望的那样:
如果你打开programming.txt,将发现两行内容挤在一起:
要让每个字符串都单独占一行,需要在write()语句中包含换行符:
现在,输出出现在不同行中:
10.2.3 附加到文件
如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件。你以附加模式
打开文件时, Python不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾。
如果指定的文件不存在, Python将为你创建一个空文件。
输出后:
最终的结果是,文件原来的内容还在,它们后面是我们刚添加的内容
10.3 异常
Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Python不知
所措的错误时,它都会创建一个异常对象。
异常是使用try-except代码块处理的。 try-except代码块让Python执行指定的操作,同时告
诉Python发生异常时怎么办。使用了try-except代码块时,即便出现异常,程序也将继续运行:
显示你编写的友好的错误消息,而不是令用户迷惑的traceback。
10.3.1 处理 ZeroDivisionError 异常
10.3.2 使用 try-except 代码块
当你认为可能发生了错误时,可编写一个try-except代码块来处理可能引发的异常。你让Python尝试运行一些代码,并告诉它如果这些代码引发了指定的异常,该怎么办。
处理ZeroDivisionError异常的try-except代码块类似于下面这样:
0.3.3 使用异常避免崩溃
发生错误时,如果程序还有工作没有完成,妥善地处理错误就尤其重要。这种情况经常会出
现在要求用户提供输入的程序中;如果程序能够妥善地处理无效输入,就能再提示用户提供有效
输入,而不至于崩溃。
下面来创建一个只执行除法运算的简单计算器:
这个程序没有采取任何处理错误的措施,因此让它执行除数为0的除法运算时,它将崩溃:
10.3.4 else 代码块
通过将可能引发错误的代码放在try-except代码块中,可提高这个程序抵御错误的能力。错
误是执行除法运算的代码行导致的,因此我们需要将它放到try-except代码块中。这个示例还包
含一个else代码块;依赖于try代码块成功执行的代码都应放到else代码块中:
程序将继续运行,用户根本看不到traceback:
10.3.5 处理 FileNotFoundError 异常
我们来尝试读取一个不存在的文件。下面的程序尝试读取文件alice.txt的内容,但我没有将
这个文件存储在alice.py所在的目录中:
因此要处理这个错误,必须将try语句放在包含open()的代码行之前:
10.3.6 分析文本
本节使用的文本来自项目Gutenberg( http://gutenberg.org/),这个项目提
供了一系列不受版权限制的文学作品,如果你要在编程项目中使用文学文本,这是一个很不错的
资源 。
下面来提取童话Alice in Wonderland的文本,并尝试计算它包含多少个单词。我们将使用方
法split(),它根据一个字符串创建一个单词列表。下面是对只包含童话名"Alice in Wonderland"的字符串调用方法split()的结果:
结果是一个包含字符串中所有单词的列表
方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中 。
10.4 存储数据
很多程序都要求用户输入某种信息,如让用户存储游戏首选项或提供要可视化的数据。不管
专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中。用户关闭程序时,你
几乎总是要保存他们提供的信息;一种简单的方式是使用模块json来存储数据 。
模块json让你能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件
中的数据。
10.4.1 使用 json.dump()和 json.load()
函数json.dump()接受两个实参:要存储的数据以及可用于存储数据的文件对象。
下面演示 了如何使用json.dump()来存储数字列表:
数据的存储格式与Python中一样:
下面再编写一个程序,使用json.load()将这个列表读取到内存中:
输出