第十章:文件和异常
10.1 从文件中读取数据
- 文本文件(.txt): 可存储不同的数据
10.1.1 读取整个文件
任务: 打开并读取“pi_digits.txt”,再将其内容显示到屏幕上
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)
- open() 函数用于创建或打开指定文件,该函数的常用语法格式如下:
file = open(file_name [, mode=‘r’ [ , buffering=-1 [ , encoding = None ]]])
此格式中,用 [] 括起来的部分为可选参数,即可以使用也可以省略。
-
open()返回一个表示文件的对象。open(‘pi_digits.txt’) 返回一个表示pi_digits.txt的对象,并将该对象赋给
file_object
供以后使用。 -
mode:可选参数,用于指定文件的打开模式。open() 函数支持的文件打开模式如下:(默认:只读模式)
- r 只读模式打开文件,读文件内容的指针会放在文件的开头。
- rb 以二进制格式、采用只读模式打开文件,读文件内容的指针位于文件的开头,一般用于非文本文件,如图片文件、音频文件等。
- r+ 打开文件后,既可以从头读取文件内容,也可以从开头向文件中写入新的内容,写入的新内容会覆盖文件中等长度的原有内容。
- rb+ 以二进制格式、采用读写模式打开文件,读写文件的指针会放在文件的开头,通常针对非文本文件(如音频文件)。
- w 以只写模式 打开文件,若该文件存在,打开时会清空文件中原有的内容。 若文件存在,会清空其原有内容(覆盖文件);反之,则创建新文件。
- wb 以二进制格式、只写模式打开文件,一般用于非文本文件(如音频文件)
- w+ 打开文件后,会对原有内容进行清空,并对该文件有读写权限。
- wb+ 以二进制格式、读写模式打开文件,一般用于非文本文件
- a 以追加模式打开一个文件,对文件只有写入权限,如果文件已经存在,文件指针将放在文件的末尾(即新写入内容会位于已有内容之后);反之,则会创建新文件。
- ab 以二进制格式打开文件,并采用追加模式,对文件只有写权限。如果该文件已存在,文件指针位于文件末尾(新写入文件会位于已有内容之后);反之,则创建新文件。
- a+ 以读写模式打开文件;如果文件存在,文件指针放在文件的末尾(新写入文件会位于已有内容之后);反之,则创建新文件。
- ab+ 以二进制模式打开文件,并采用追加模式,对文件具有读写权限,如果文件存在,则文件指针位于文件的末尾(新写入文件会位于已有内容之后);反之,则创建新文件。
-
关键字with在不需要访问文件后将其关闭。
-
read()读取对象
file_object
的全部内容,并将其作为一个长字符串赋给变量contents
。 -
输出的末尾多了一个空行。因为read()到达文件末尾时返回一个空字符串,将空字符串显示出来就是一个空行。
-
要删除空行,可在
print()
中使用rstrip()
。
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents.rstrip())
10.1.2 文件路径
-
将文件
pi_digits.txt
传递给open()
时,Python在当前执行的文件所在的目录中查找文件 -
要打开不在程序文件所属目录的文件,需要提供文件路径, 让Python到特定文件夹中去寻找。
-
相对路径: 相对于当前运行程序所在的目录,例:text_files/pi_digits.txt
-
绝对路径: 文件在计算机中的准确位置,例:D:\OneDrive - yangtzeu.edu.cn\Python_projects\python_notebook\text_files\pi_digits.txt
注意:
1. 显示文件路径时,Windows系统使用反斜杠(\)而不是斜杠(/),但在代码中可以使用斜杠(/)。
2. 在文件路径中直接使用反斜杠(\)将引发错误。因为Python中反斜杠(\)用于对字符串的字符进行转义。如直接使用‘D:\OneDrive - yangtzeu.edu.cn\Python_projects\python_notebook\text_files\pi_digits.txt’将报错,因为\t将被理解为制表符。
解决方法:
1.在路径中使用斜杠(/);
2.如果一定要使用反斜杠,可对每个反斜杠进行转义,即使用“\”。
with open('text_files/pi_digits.txt') as file_object:
contents = file_object.read()
print(contents.rstrip())
file_path = '/python_notebook/text_files\pi_digits.txt'
with open(file_path) as file_object:
contents = file_object.read()
print(contents.rstrip())
file_path = '\\python_notebook\\text_files\\pi_digits.txt'
with open(file_path) as file_object:
contents = file_object.read()
print(contents.rstrip())
10.1.3 逐行读取
- 任务: 以每次一行的方式检查文件
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line)
3.1415926535
8979323846
2643383279
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line.strip())
3.1415926535
8979323846
2643383279
10.1.4 创建一个包含文件各行内容的列表
- 使用关键字
with
时,open()
返回的文件对象只在with
代码块内可使用。如果要在with
代码块外访问文件内容,可在with
代码块内将文件的各行存储在一个列表中,并在with
代码块外使用该列表。
任务: 在with
代码块中将文件pi_digits.txt的各行存储在一个列表中,再在with
代码块外打印。
filename = 'pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines() #readlines()从文件中读取每一行并存储在一个列表中
for line in lines:
print(line.strip())
3.1415926535
8979323846
2643383279
10.1.5 使用文件的内容
任务: 创建一个字符串,包含文件中存储的所有数字且没有空格。
filename = '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))
3.1415926535 8979323846 2643383279
36
filename = 'pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
print(pi_string)
print(len(pi_string))
3.141592653589793238462643383279
32
注意:
-
strip()
与rstrip()
的区别。 -
读取文本文件时,Python将其中所有的文本都解读为字符串。如果读取的是数,并要将其作为数值使用,必须使用
int()
或float()
将其转换为整数或小数。
10.1.6 包含一百万位的大型文件
任务: 打开并读取“pi_million_digits.txt”,并打印小数点后50位
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))
10.1.7 圆周率中包含你的生日吗
任务: 确定某人的生日是否包含在圆周率的前一百万位中
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()
birthday = input("Enter your birthday, in the from mmddyy: ")
if birthday in pi_string:
print("Your birthday appears in the first million digits of pi!")
else:
print("Your birthday does not appear in the first million digits of pi!")
10.2 写入文件——write()
- 保存数据最简单的方式是将其写入文件中
10.2.1 写入空文件
filename = 'programming.txt'
with open(filename, 'w') as file_object:
file_object.write("I love programming.")
- write()将一个字符串写入文件
- 写入模式‘w’
- 若要写入的文件不存在,open()将自动创建
- 若文件存在,会清空其原有内容(覆盖文件)
- Python只能将字符串写入文本文件,要将数值数据存储到文本文件中,必须先用str()将数值转化为字符串格式
10.2.2 写入多行
filename = 'programming.txt'
with open(filename, 'w') as file_object:
file_object.write("I love programming.\n")
file_object.write("I love create new games.\n")
10.2.3 附加到文件
- 附加模式‘a’ : 不会清空文件的内容,而是将写入文件的行添加到文件末尾
filename = 'programming.txt'
with open(filename, 'a') as file_object:
file_object.write("I also love mathematics.\n")
10.3 异常
- Python使用称为异常 的特殊对象来管理程序执行期间发生的错误。
- 异常使用
try-except
代码块处理。
10.3.1 处理ZeroDivisionError
异常
print(5/0)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-4-fad870a50e27> in <module>
----> 1 print(5/0)
ZeroDivisionError: division by zero
10.3.2 使用try-except
代码块
- 当你认为可能会发生错误时,可编写一个
try-except
代码块来处理可能引发的异常
try:
print(5/0)
except ZeroDivisionError:
print("You can not divide by zero!")
You can not divide by zero!
- 如果
try
代码块中代码运行起来没问题,Python将跳过except
代码块 - 如果
try
代码块中代码导致了错误,Python将查找与之匹配的except
代码块并运行其中的代码 - 如果
try-except
代码块后面还有其他代码,程序将继续运行。
10.3.3 使用异常避免崩溃
print("Give me two numbers, and I will divide them.")
print("Enter 'q' to quit.")
while True:
first_number = input("\n First number: ")
if first_number == 'q':
break
second_number = input("\n Second number: ")
if second_number == 'q':
break
answer = int(first_number)/int(second_number)
print(answer)
Give me two numbers, and I will divide them.
Enter 'q' to quit.
First number: 5
Second number: 0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-9-dae5a3a0f8f7> in <module>
9 if second_number == 'q':
10 break
---> 11 answer = int(first_number)/int(second_number)
12 print(answer)
ZeroDivisionError: division by zero
10.3.4 else
代码块
- 通过将可能引发错误的代码放在
try-except
代码块中,可提高程序抵御错误的能力
print("Give me two numbers, and I will divide them.")
print("Enter 'q' to quit.")
while True:
first_number = input("\n First number: ")
if first_number == 'q':
break
second_number = input("\n Second number: ")
if second_number == 'q':
break
try:
answer = int(first_number)/int(second_number)
except ZeroDivisionError:
print("You can not divide by zero!")
else:
print(answer)
try-except-else
代码块的工作原理:- 只有有可能引发异常的代码才需要放在
try
代码块中 - 仅在
try
代码块成功执行时才需要运行的代码放在else
代码块中 - 尝试运行
try
代码块时引发指定错误该如何处理放在except
代码块中
- 只有有可能引发异常的代码才需要放在
10.3.5 处理FileNotFoundError
异常
任务: 尝试读取一个不存在的文件
filename = 'alice.txt'
with open(filename, encoding='utf-8') as f: #系统默认编码与读取文件编码不一致时,要指定encoding参数
content = f.read()
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-13-763ac173c0f0> in <module>
1 filename = 'alice.txt'
2
----> 3 with open(filename, encoding='utf-8') as f: #系统默认编码与读取文件编码不一致时,要指定encoding参数
4 content = f.read()
FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
file_name = 'alice.txt'
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {filename} does not exit!")
Sorry, the file alice.txt does not exit!
10.3.6 分析文本
- split(): 根据字符串创建一个单词列表
file_name = 'alice.txt'
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {filename} does not exit!")
else:
#计算该文件中大致包含多少个单词
words = contents.split()
num_words = len(words)
print(f"The file {filename} has about {num_words} words.")
The file alice.txt has about 29465 words.
10.3.7 使用多个文件
def count_words(filename):
"统计一个文件大致包含多少个单词"
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {filename} does not exit!")
else:
#计算该文件中大致包含多少个单词
words = contents.split()
num_words = len(words)
print(f"The file {filename} has about {num_words} words.")
filename = 'alice.txt'
count_words(filename)
The file alice.txt has about 29465 words.
def count_words(filename):
"统计一个文件大致包含多少个单词"
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {filename} does not exit!")
else:
#计算该文件中大致包含多少个单词
words = contents.split()
num_words = len(words)
print(f"The file {filename} has about {num_words} words.")
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words(filename)
The file alice.txt has about 29465 words.
Sorry, the file siddhartha.txt does not exit!
The file moby_dick.txt has about 215830 words.
The file little_women.txt has about 189079 words.
10.3.8 静默失败
- 并非每次捕获到的异常都需要告诉用户,有时候希望程序在异常时保持静默
- 使用pass语句
def count_words(filename):
"统计一个文件大致包含多少个单词"
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
#print(f"Sorry, the file {filename} does not exit!")
pass
else:
#计算该文件中大致包含多少个单词
words = contents.split()
num_words = len(words)
print(f"The file {filename} has about {num_words} words.")
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words(filename)
The file alice.txt has about 29465 words.
The file moby_dick.txt has about 215830 words.
The file little_women.txt has about 189079 words.
10.3.9 决定报告哪些错误
10.4 存储数据
- 模块
json
(JavaScript Object Notation,Json)可以将简单的python数据结构转储到文件中,并在程序再次运行时加载改文件中的数据
10.4.1 存储json.dump()
和读取json.load()
import json
numbers = [2,3,5,7,9,11]
filename = 'number.json'
with open(filename, 'w') as f:
json.dump(numbers,f)
import json
filename = 'number.json'
with open(filename) as f:
numbers = json.load(f)
print(numbers)
10.4.2 保存和读取用户生成的数据
任务: 提示用户首次运行程序是输入自己的名字,并在再次运行程序是记住他
#存储用户的名字
import json
username = input("What is your name?")
filename = "username.json"
with open(filename,'w') as f:
json.dump(username, f)
print(f"We will remember you when you come back, {username}!")
What is your name?Eric
We will remember you when you come back, Eric!
# 向已存储的用户发出问候
import json
filename = "username.json"
with open(filename) as f:
username = json.load(f)
print(f"Welcome back, {username}!")
#如果以前已经存储了用户的名字,则load,否则提示用户输入并存储
import json
filename = "username.json"
try:
with open(filename) as f:
username = json.load(f)
except FileNotFoundError:
username = input("What is your name?")
with open(filename,'w') as f:
json.dump(username, f)
print(f"We will remember you when you come back, {username}!")
else:
print(f"Welcome back, {username}!")
10.4.3 重构
import json
def greet_user():
"问候用户,并指出名字"
filename = "username.json"
try:
with open(filename) as f:
username = json.load(f)
except FileNotFoundError:
username = input("What is your name?")
with open(filename,'w') as f:
json.dump(username, f)
print(f"We will remember you when you come back, {username}!")
else:
print(f"Welcome back, {username}!")
greet_user()
import json
def get_stored_username():
"如果用户名已存储,则加载"
filename = "username.json"
try:
with open(filename) as f:
username = json.load(f)
except FileNotFoundError:
return None
else:
return username
def greet_user():
"问候用户,并指出名字"
username = get_stored_username()
if username:
print(f"Welcome back, {username}!")
else:
username = input("What is your name?")
filename = "username.json"
with open(filename,'w') as f:
json.dump(username, f)
print(f"We will remember you when you come back, {username}!")
greet_user()
import json
def get_stored_username():
"如果用户名已存储,则加载"
filename = "username.json"
try:
with open(filename) as f:
username = json.load(f)
except FileNotFoundError:
return None
else:
return username
def get_new_username():
"提示用户输入用户名"
username = input("What is your name?")
filename = "username.json"
with open(filename,'w') as f:
json.dump(username, f)
return username
def greet_user():
"问候用户,并指出名字"
username = get_stored_username()
if username:
print(f"Welcome back, {username}!")
else:
username = get_new_username()
print(f"We will remember you when you come back, {username}!")
greet_user()