9.1 从文件中读取数据
要使用文本文件中的信息,首先需要将信息读取到内存中。为此,你可以<u>一次性读取文件的</u>
<u>全部内容</u>,<u>也可以以每次一行的方式逐步读取</u>.
9.1.1 读取整个文件
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)
在这个示例中, 当前运行的是file_reader.py,因此Python在file_reader.py所在的目录中查找pi_digits.txt。函数open() 返回一个表示文件的对象。在这里,open('pi_digits.txt')返回一个表示文件pi_digits.txt的对
象;Python将这个对象存储在我们将在后面使用的变量(file_object)中。
注意:不必显示调用close()方法来关闭文件。可让Python去确定:你只管打开文件,并在需要时使用它,Python自会在合适的时候自动将其关闭。
使用方法read()(前述程序的第2行)读取这个文 件的全部内容,并将其作为一个长长的字符串存储在变量contents中。这样,通过打印contents 的值,就可将这个文本文件的全部内容显示出来:
3.1415926535
8979323846
2643383279
相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。为何会多出这个空行呢?因
为read()到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删
除多出来的空行,可在print语句中使用rstrip()。
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents.rstrip())
#输出结果:
3.1415926535
8979323846
2643383279
9.1.2 文件路径
相对文件路径
在Linux和OS X中,你可以这样编写代码:
with open('text_files/filename.txt') as file_object:
Windows系统中,在文件路径中使用反斜杠(\)而不是斜杠(/):
with open('text_files*filename*.txt') as file_object:
绝对文件路径
绝对路径通常比相对路径更长,因此将其存储在一个变量中,再将该变量传递给open()会有
所帮助。
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object:
9.1.3 逐行读取---可对文件对象使用for循环
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line)
由于变量filename表示的并非实际文件——它只是一个让Python知道到哪里去查找文件的字
符串。
问题:
3.1415926535
8979323846
2643383279
为何会出现这些空白行呢?因为在这个文件中,每行的末尾都有一个看不见的换行符,而
print语句也会加上一个换行符,因此每行末尾都有两个换行符:一个来自文件,另一个来自print
语句。要消除这些多余的空白行,可在print语句中使用rstrip():
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line.rstrip())
#结果:
3.1415926535
8979323846
2643383279
9.1.4 创建一个包含文件各行内容的列表
在with代码块外访问文件的内容,可在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表。
filename = 'pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
for line in lines:
print(line.rstrip())
9.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() ###pi_string += line.strip()
print(pi_string)
print(len(pi_string))
#输出:
3.1415926535 8979323846 2643383279
36
在变量pi_string存储的字符串中,包含原来位于每行左边的空格,为删除这些空格,可使
用strip()。
9.1.6 查找一个字符串是否包含于另一个字符串中
example:将生日表示为一个由数字组成的字符 串,再检查这个字符串是否包含在pi_string中
filename = 'pi_million_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.rstrip()
birthday = input("Enter your birthday, in the form 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.")
9.2 写入文件
9.2.1 写入空文件
filename = 'programming.txt'
with open(filename, 'w') as file_object: ##filename是文件路径
file_object.write("I love programming.")
注意:你省略了模式实参,Python将以默认的只读模式打开文件;
如果你要写入的文件不存在,函数open()将自动创建它。
因为如果指定的文件已经存在,Python将在返回文件对象前清空该文件。
Python只能将字符串写入文本文件。存数值时必须先用str()将其转化为字符串。
9.2.2 写入多行
函数write()不会在你写入的文本末尾添加换行符,因此如果你写入多行时没有指定换行符
如:需要手动单独添加“\n、\t等”
9.2.3 附加文件(以“a”的方式打开文件)
如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件。Python不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾。
如果指定的文件不存在,Python将为你创建一个空文件。
filename = 'programming.txt'
with open(filename, 'a') as file_object:
file_object.write("I also love finding meaning in large datasets.\n")
file_object.write("I love creating apps that can run in a browser.\n")
我们打开文件时指定了实参'a',以便将内容附加到文件末尾,而不是覆盖文件原
来的内容
9.3 异常
异常通过try-except代码块处理的,类似于Java中的try-catch代码块。
9.3.1 处理ZeroDivisionError异常(除零异常)
print(5/0)
#结果:
Traceback (most recent call last):
File "division.py", line 1, in <module>
print(5/0)
ZeroDivisionError: division by zero
9.3.2 使用try-except代码块
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide by zero!")
9.3.3 else代码块
print("Give me two numbers, and I'll divide them.")
print("Enter 'q' to quit.")
while True:
first_number = input("\nFirst number: ")
if first_number == 'q':
break
second_number = input("Second number: ")
try:
answer = int(first_number) / int(second_number)
except ZeroDivisionError:
print("You can't divide by 0!")
else:
print(answer)
行try代码块中只包含可能导致错误的 代码,依赖于try代码块成功执行的代码都放在else代码块中
总结:try-except-else代码块的工作原理:
<u>Python尝试执行try代码块中的代码;只有可能引发异常的代码才需要放在try语句中。有时候,有一些仅在try代码块成功执行时才需要运行 的代码;这些代码应放在else代码块中。except代码块告诉Python,如果它尝试运行try代码块中 的代码时引发了指定的异常,该怎么办。</u>
9.3.4 处理FileNotFoundError异常
example:下面的程序尝试读取文件alice.txt的内容,但我没有将这个文件存储在alice.py所在的目录中:
filename = 'alice.txt'
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry, the file " + filename + " does not exist."
print(msg)
#结果:
9.3.5 分析文本
example:来提取童话Alice in Wonderland的文本,并尝试计算它包含多少个单词记住split()函数。
(split()函数根据一个字符串创建一个单词列表)
方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。
结果是一个包含字符串中所有单词的列表,虽然有些单词可能包含标点
filename = 'alice.txt'
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry, the file " + filename + " does not exist."
print(msg)
else:
# 计算文件大致包含多少个单词
words = contents.split()
num_words = len(words)
print("The file " + filename + " has about " + str(num_words) + " words.")
#输出:
The file alice.txt has about 29461 words.
9.3.6 使用多个文件
声明函数:
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry, the file " + filename + " does not exist."
print(msg)
else:
# 计算文件大致包含多少个单词
words = contents.split()
num_words = len(words)
print("The file " + filename + " has about " + str(num_words) +
" words.")
filename = 'alice.txt'
count_words(filename)
调用函数:
def count_words(filename):
--snip--
、
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words(filename)
结果输出:
The file alice.txt has about 29461 words.
Sorry, the file siddhartha.txt does not exist.
The file moby_dick.txt has about 215136 words.
The file little_women.txt has about 189079 words.
9.3.7 出现异常时跳过不处理
有时候你希望程序在发生异常时一声不吭,就像什么都没有发生一样继续运行。要让程序在
失败时一声不吭,可像通常那样编写try代码块,但在except代码块中明确地告诉Python什么都不
要做。Python有一个pass语句,可在代码块中使用它来让Python什么都不要做
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
--snip--
except FileNotFoundError:
pass ##这种错误发生时,不会出现traceback,也没有任何输出
else:
--snip--
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words(filename)
此点的应用:pass语句还充当了占位符,它提醒你在程序的某个地方什么都没有做,并且以后也许要在这
里做些什么。例如,在这个程序中,我们可能决定将找不到的文件的名称写入到文件
missing_files.txt中。用户看不到这个文件,但我们可以读取这个文件,进而处理所有文件找不到
的问题。
9.4 存储数据----模块json
9.4.1 使用json.dump()和json.load()
json.dump():用于存储数据。
json.load():用于将数据读取到内存中
- 函数json.dump()接受两个实参:要存储的数据以及可用于存储数据的文件对象
import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as f_obj:
json.dump(numbers, f_obj)
#输出:[2, 3, 5, 7, 11, 13]
以写入模式打开这个文件,让json能够将数据写入其中(见第六行)。在处,我们使用函数json.dump()
将数字列表存储到文件numbers.json中。
2.将数据读取到内存中
import json
filename = 'numbers.json'
with open(filename) as f_obj:
numbers = json.load(f_obj)
print(numbers)
#输出:
[2, 3, 5, 7, 11, 13]
9.4.2 保存和读取用户生成的数据
import json
# 如果以前存储了用户名,就加载它
# 否则,就提示用户输入用户名并存储它
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("What is your name? ")
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
else:
print("Welcome back, " + username + "!")
若程序首次运行将输出:
What is your name? Eric
We'll remember you when you come back, Eric!
否则,输出将如下:
Welcome back, Eric!
9.4.3 重构 ----将代码划分为一系列完成具体工作的函数
import json
def get_stored_username():
"""如果存储了用户名,就获取它"""
--snip--
def get_new_username():
"""提示用户输入用户名"""
username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
return username
def greet_user():
"""问候用户,并指出其名字"""
username = get_stored_username()
if username:
print("Welcome back, " + username + "!")
else:
username = get_new_username()
print("We'll remember you when you come back, " + username + "!")
greet_user()
在remember_me.py的这个最终版本中,每个函数都执行单一而清晰的任务。我们调用
greet_user(),它打印一条合适的消息:要么欢迎老用户回来,要么问候新用户。为此,它首先
调用get_stored_username(),这个函数只负责获取存储的用户名(如果存储了的话),再在必要
时调用get_new_username(),这个函数只负责获取并存储新用户的用户名。