《Python编程:从入门到实践》第 10 章 文件和异常

目录

10.1 从文件中读取数据

10.1.1 读取整个文件

10.1.2 文件路径

 10.1.3 逐行读取

10.1.4 创建一个包含文件各行内容的列表

10.1.5 使用文件的内容

 10.1.6 包含一百万位的大型文件

 10.1.7 练习

练习10-1:Python学习笔记

练习10-2:C语言学习笔记

10.2 写入文件

10.2.1 写入空文件

10.2.2 写入多行 

10.2.3 附加到文件

10.2.4 练习

练习10-3:访客

练习10-4:访客名单

练习10-5:调查

10.3 异常

10.3.1 处理ZeroDivisionError 异常

10.3.2 使用try-except 代码块

10.3.3 使用异常避免崩溃

10.3.4 else 代码块

10.3.5 处理FileNotFoundError 异常

10.3.6 分析文本

10.3.7 使用多个文件

10.3.8 静默失败

10.3.9 决定报告哪些错误

10.3.10 练习

练习10-6:加法运算

练习10-7:加法计算器

练习10-8:猫和狗

练习10-9:静默的猫和狗

练习10-10:常见单词

10.4 存储数据

 10.4.1 使用json.dump() 和json.load()

10.4.2 保存和读取用户生成的数据

10.4.3 重构

10.4.4 练习

练习10-11:喜欢的数

练习10-12:记住喜欢的数

练习10-13:验证用户


 

10.1 从文件中读取数据

文本文件可存储的数据量多得难以置信:天气数据、交通数据、社会经济数据、文学作品等。每当需要分析或修改存储在文件中的信息时,读取文件都很有用,对数据分析应用程序来说尤其如此。例如,可以编写一个这样的程序:读取一个文本文件的内容,重新设置这些数据的格式并将其写入文件,让浏览器能够显示这些内容。

要使用文本文件中的信息,首先需要将信息读取到内存中。为此,你可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取。

10.1.1 读取整个文件

要读取文件,需要一个包含几行文本的文件。下面首先创建一个文件,它包含精确到小数点后30位的圆周率值,且在小数点后每10位处换行:
3.1415926535
  8979323846
  2643383279
要动手尝试后续示例,可在编辑器中输入这些数据行,再将文件保存为pi_digits.txt,请将该文件保存到本章程序所在的目录。
下面的程序打开并读取这个文件,再将其内容显示到屏幕上:
with open('D:\\python_work\\chapter10\\pi_digits.txt') as file_object:
    contents = file_object.read()
print(contents)
在这个程序中,第一行代码做了大量的工作。我们先来看看函数 open() 。要以任何方式使用文件,那怕仅仅是打印其内容,都得先打开 文件,才能访问它。函数open() 接受一个参数:要打开的文件的名称。Python在当前执行的文件所在的目录中查找指定的文件。在本例中,当前运行的是file_reader.py,因此Python在file_reader.py所在的目录中查找pi_digits.txt。函数 open() 返回一个表示文件的对象。在这里, open('pi_digits.txt') 返回一个表示文件pi_digits.txt的对象,Python将该对象赋给 file_object 供以后使用。
关键字 with 在不再需要访问文件后将其关闭。在这个程序中,注意到我们调用了open() ,但没有调用 close() 。也可以调用 open() close() 来打开和关闭 文件,但这样做时,如果程序存在bug导致方法close() 未执行,文件将不会关闭。这看似微不足道,但未妥善关闭文件可能导致数据丢失或受损。如果在程序中过早调用 close() ,你会发现需要使用文件时它已关闭 (无法访问),这会导致更多的错误。并非在任何情况下都能轻松确定关闭文件的恰当时机,但通过使用前面所示的结构,可让Python去确定:你只管打开文件,并在需要时使用它,Python自会在合适的时候自动将其关闭。
有了表示pi_digits.txt的文件对象后,使用方法 read() (前述程序的第二行)读取这个文件的全部内容,并将其作为一个长长的字符串赋给变量 contents 。这样,通过打印 contents 的值,就可将这个文本文件的全部内容显示出来:
3.1415926535
  8979323846
  2643383279

10.1.2 文件路径

将类似于pi_digits.txt的简单文件名传递给函数open() 时,Python将在当前执行的文件(即.py程序文件)所在的目录中查找。

根据你组织文件的方式,有时可能要打开不在程序文件所属目录中的文件。例如,你可能将程序文件存储在了文件夹python_work中,而该文件夹中有一个名为text_files的文件夹用于存储程序文件操作的文本文件。虽然文件夹text_files包含在文件夹python_work中,但仅向open() 传递位于前者中的文件名称也不可行,因为Python只在文件夹python_work中查找,而不会在其子文件夹text_files中查找。要让Python打开不与程序文件位于同一个目录中的文件,需要提供文件路径,让Python到系统的特定位置去查找。由于文件夹text_files位于文件夹python_work中,可以使用相对文件路径来打开其中的文件。相对文件路径让Python到指定的位置去查找,而该位置是相对于当前运行的程序所在目录的。例如,可这样编写代码:
with open('text_files/filename.txt') as file_object:
这行代码让Python到文件夹python_work下的文件夹text_files中去查找指定的.txt文件。
注意         示文件路径时,Windows系统使用反斜杠(\ )而不是斜杠( / ),但在代码中依然可以使用斜杠。

 还可以将文件在计算机中的准确位置告诉Python,这样就不用关心当前运行的程序存储在什么地方了。这称为绝对文件路径 。在相对路径行不通时,可使用绝对路径。例如,如果text_files并不在文件夹python_work中,而在文件夹other_files中,则向open() 传递路径'text_files/filename .txt' 行不通,因为Python只在文件夹python_work中查找该位置。为明确指出希望Python到哪里去查找,需要提供完整的路径。

绝对路径通常比相对路径长,因此将其赋给一个变量,再将该变量传递给open()会有所帮助
file_path = '/home/ehmatthes/other_files/text_files/_filename_.txt'
with open(file_path) as file_object:

通过使用绝对路径,可读取系统中任何地方的文件。就目前而言,最简单的做法是,要么将数据文件存储在程序文件所在的目录,要么将其存储在程序文件所在目录下的一个文件夹(如text_files)中。

注意         如果在文件路径中直接使用反斜杠,将引发错误,因为反斜杠用于对字符串中的字符进行转义。例如,对于路径 "C:\path\to\file.txt" ,其中的 \t 将被解读为制表符。如果一定要使用反斜杠,可对路径中的每个反斜杠都进行转义,如 "C:\\path\\to\\file.txt"

 10.1.3 逐行读取

读取文件时,常常需要检查其中的每一行:可能要在文件中查找特定的信息,或者要以某种方式修改文件中的文本。例如,你可能要遍历一个包含天气数据的文件,并使用天气描述中包含sunny字样的行。在新闻报道中,你可能会查找包含标签<headline> 的行,并按特定的格式设置它。
要以每次一行的方式检查文件,可对文件对象使用 for 循环:
filename = 'D:\\python_work\\chapter10\\pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line)
将要读取的文件的名称赋给变量 filename 。这是使用文件时的一种常见做法。变量 filename 表示的并非实际文件——它只是一个让Python知道到哪里去查找文件的字符串,因此可以轻松地将 'pi_digits.txt' 替换为要使用的另一个文件的名称。调用 open() 后,将一个表示文件及其内容的对象赋给了变量file_object 。这里也使用了关键字with ,让Python负责妥善地打开和关闭文件。为查看文件的内容,通过对文件对象执行循环来遍历文件中的每一行
打印每一行时,发现空白行:
3.1415926535

  8979323846

  2643383279
为何会出现这些空白行呢?因为在这个文件中,每行的末尾都有一个看不见的换行符,而函数调用 print() 也会加上一个换行符,因此每行末尾都有两个换行符:一个来自文件,另一个来自函数调用 print() 。要消除这些多余的空白行,可在函数调用 print() 中使用 rstrip()
filename = 'D:\\python_work\\chapter10\\pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line.rstrip())
现在,输出又与文件内容完全相同了:
3.1415926535
  8979323846
  2643383279

10.1.4 创建一个包含文件各行内容的列表

使用关键字 with 时, open() 返回的文件对象只在 with 代码块内可用。如果要在 with 代码块外访问文件的内容,可在 with 代码块内将文件的各行存储在一个列 表中,并在 with 代码块外使用该列表:可以立即处理文件的各个部分,也可以推迟到程序后面再处理。
下面的示例在 with 代码块中将文件pi_digits.txt的各行存储在一个列表中,再在with 代码块外打印:
filename = 'D:\\python_work\\chapter10\\pi_digits.txt'
with open(filename) as file_object:
    lines = file_object.readlines()

for line in lines:
    print(line.rstrip())
方法 readlines() 从文件中读取每一行,并将其存储在一个列表中。接下来,该列表被赋给变量 lines 。在 with 代码块外,依然可使用这个变量。 使用一个简单的 for 循环来打印 lines 中的各行。因为列表 lines 的每个元素都对应于文件中的一行,所以输出与文件内容完全一致。

10.1.5 使用文件的内容

将文件读取到内存中后,就能以任何方式使用这些数据了。下面以简单的方式使用圆周率的值。首先,创建一个字符串,它包含文件中存储的所有数字,且没有任何空格:
filename = 'D:\\python_work\\chapter10\\pi_digits.txt'
with open(filename) as file_object:
    lines = file_object.readlines()
pi_string = ''
for line in lines:
    pi_string += line.rstrip()

print(pi_string)
print(len(pi_string))
像前一个示例一样,首先打开文件,并将其中所有的行都存储在一个列表中。创建了一个变量 pi_string ,用于指向圆周率的值。接下来,使用一个循环将各行加入 pi_string ,并删除每行末尾的换行符 。打印这个字符串及其长度:
3.1415926535 8979323846 2643383279
36
变量 pi_string 指向的字符串包含原来位于每行左边的空格,为删除这些空格,可使用 strip() 而非 rstrip()
--snip--
for line in lines:
    pi_string += line.strip()
print(pi_string)
print(len(pi_string))
这样就获得了一个字符串,其中包含准确到30位小数的圆周率值。这个字符串长32字符,因为它还包含整数部分的3和小数点:
3.141592653589793238462643383279
32
注意         读取文本文件时,Python将其中的所有文本都解读为字符串。如果读取的是数,并要将其作为数值使用,就必须使用函数 int() 将其转换为整数或使用函数 float() 将其转换为浮点数。

 10.1.6 包含一百万位的大型文件

前面分析的都是一个只有三行的文本文件,但这些代码示例也可处理大得多的文件。如果我们有一个文本文件,其中包含精确到小数点后1 000 000位而不是30位的圆周率值,也可创建一个包含所有这些数字的字符串。为此,无须对前面的程序做任何修改,只要将这个文件传递给它即可。在这里,只打印到小数点后50位,以免终端为显示全部1 000 000位而不断滚动:
filename = 'pi_million_digits.txt'
with open(filename) as file_object:
    lines = file_object.readlines()

pi_string = ''
for line in lines:
    pi_string += line.strip()

print(f"{pi_string[:52]}...")
print(len(pi_string))
输出表明,创建的字符串确实包含精确到小数点后1 000 000位的圆周率值:
3.14159265358979323846264338327950288419716939937510...
1000002
对于可处理的数据量,Python没有任何限制。只要系统的内存足够多,你想处理多少数据都可以。

 10.1.7 练习

练习10-1:Python学习笔记

在文本编辑器中新建一个文件,写几句话来总结一下你至此学到的Python知识,其中每一行都以“In Python you can”打头。将这个文件命名为learning_python.txt,并存储到为完成本章练习而编写的程序所在的目录中。编写一个程序,它读取这个文件,并将你所写的内容打印三次:第一次打印时读取整个文件;第二次打印时遍历文件对象;第三次打印时将各行存储在一个列表中,再在 with 代码块外打印它们。
file_name = 'D:\\python_work\\chapter10\\practice10_1.txt'
with open(file_name) as file_object:
    print(file_object)
    lines = file_object.readlines()
    print(lines)

for line in lines:
    print(line.rstrip())

练习10-2:C语言学习笔记

可使用方法 replace() 将字符串中的特定单词都替换为另一个单词。下面是一个简单的示例,演示了如何将句子中的'dog'替换为 'cat'
file_name = 'D:\\python_work\\chapter10\\practice10_1.txt'
with open(file_name) as file_object:
    print(file_object)
    lines = file_object.readlines()
    print(lines)

for line in lines:
    line = line.rstrip()
    print(line.replace('python', 'C'))

10.2 写入文件

保存数据的最简单的方式之一是将其写入文件中。通过将输出写入文件,即便关闭包含程序输出的终端窗口,这些输出也依然存在:可以在程序结束运行后查看这些输出,可以与别人分享输出文件,还可以编写程序来将这些输出读取到内存中并进行处理。

10.2.1 写入空文件

要将文本写入文件,你在调用open() 时需要提供另一个实参,告诉Python你要写入打开的文件。为明白其中的工作原理,我们来将一条简单的消息存储到文件中,而
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值