1.从文件中读取数据
文本文件可以储存大量的数据,如果我们要使用文本文件的信息,就必须将这些信息读取到内存中。为此,我们可以一次性读取全部内容,也可以逐行读取。
1.1读取整个文件
要读取文件,首先你得知道文件的位置。然后通过下段代码进行读取:
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)
函数open()是用来打开文件,它接受一个参数:要打开文件的名称。然后,Python会在当前文件夹所在的目录中查找指定文件。当然,这里涉及到相对路径和绝对路径的问题,我们后边再说。
关键字with在不再需要访问文件后将其关闭。注意,我们在上段代码中调用了函数open,但并未调用函数close,这是因为我们通常不确定何时要关闭文件,使用关键字with,让Python在合适的时机自己关闭文件。
当读取到文本文件中的信息后,使用方法read()读取这个文件的全部内容,并将其作为字符串赋值给变量contents。但是在打印结果时,我们会发现多了一个空白行。这时,我们可以在print()使用rstrip()来删除末尾的空白行。
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents.rstrip())
1.2文件路径
将类似于'pi_digits.txt'的简单文件名传递给函数open时,Python会在当前执行文件所在的目录中查找。
如果文本文件不在当前执行文件所在的目录,可以考虑使用相对目录(推荐使用)和绝对目录。如果要打开的文本文件所在的文件夹在当前的目录中,使用相对路径会比较简单。可以使用以下代码来调用。
with open('text_files/filename.txt') as file_object:
如果所需的文本文件不在当前文件夹所在目录下,就考虑使用绝对路径。通常绝对路径会比较长,因此要将它赋值给一个变量,再将这个变量作为参数传递给函数open。使用绝对路径可以访问系统中任何地方的文件。
file_path = '/home/ehmatthes/other_files/text_files/filename.txt'
with open(file_path) as file_object:
1.3逐行读取
读取文件,常常需要检查其中的每一行,要以每次一行的方式检查文件,可以使用for循环。
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line)
这样打印出来时,会发现每一行都多了空行,可以在print()中使用rstrip()来删除末尾的空白行。
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line.rstrip())
1.4创建一个包含文件各行内容的列表
使用关键字with时,函数open返回的文件对象只能在with代码块中使用。如果要在with代码段外使用文件中的内容,可以在with代码块内将内容存储到一个列表中。这样,调用该列表就可以使用文件中的内容了。
filename = 'chapter_10/pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
for line in lines:
print(line.rstrip())
方法readlines()从文件中读取每一行,并将其存储到一个列表中。在上段代码中,将列表赋给变量lines了。
1.5使用文件中的内容
将文件的内容读取到内存后,就可以在任何地方使用该内容了。
filename = 'chapter_10/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))
运行上述代码段,会发现在每行数据前多了空格,这是我们需要用方法strip()来删除每行左边的空格。
filename = 'chapter_10/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))
注意,Python读取文本文件时,会将所有的数据类型都解读为字符串。如果想要读取数据,并将其作为数值来使用,就必须使用函数int()和float()来将其转化为数据类型。
1.6包含百万位的大文件
读取文本文件时,我们不免会遇到一些大的文本文件。但不要害怕,我们像之前处理小的文本文件那样处理它即可。
filename = 'chapter_10/pi_million_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_million_string = ''
for line in lines:
pi_million_string += line.strip()
print(pi_million_string[:52])
print(len(pi_million_string))
在打印数据时,我们使用了切片,只打印了小数点后50位。这是因为位数过多的话终端显示时,数据会不断滚动。
2.写入文件
保存数据最简单的方式之一就事件数据保存到txt文件中去。
2.1写入空文件
要将文本写入文件,在调用函数open()时需要提供另外一个实参,告诉Python你要写入打开的文件。下面是一个简单的例子:
filename = 'programming.txt'
with open(filename, 'w') as file_object:
file_object.write("I love programming.")
在本例子中,调用函数open()时提供了两个参数,第一个参数是要打开文件的名称,第二个参数是你要以什么模式打开文件。打开文件时,你可以指定下面四种模式:
读取模式(‘r’):可以读取文件中的信息。
写入模式(‘w’):清空文件原有信息,然后在写入要输入的信息。
附加模式(‘a’):在原文件的末尾,写入要输入的信息。
读写模式(‘r+’):即以读取和写入模式打开文件。
要注意,如果忽略了第二个参数,就默认以只读的方式打开文件,如果第一个参数所指定的文件夹不存在,系统会默认建立它,并写入数据。还有,就是Python只能将字符串写入文件,如果要将数值数据写入文件,要先用str()将数值数据转化为字符串,再写入文件。
2.2写入多行
函数write()不会在写入文本的末尾添加换行符,如果要写入多行数据,要注意在函数write()中要添加信息的末尾添加换行符。
filename = 'programming.txt'
with open(filename, 'w') as file_object:
file_object.write("I love programming.\n")
file_object.write("I love creating new game.\n")
2.3附加文件
给文件添加内容,而不是要将文件原有的内容清空,可以使用附加模式。若给定的文件不存在,则创建该文件并写入数据。如果该文件存在,则在该文件的行末尾添加要写入的信息。
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.\n")
3.异常
Python使用称为异常的特殊对象来管理程序执行期间发生的错误。每当Python发生错误时,它都会创建一个异常对象。如果你编写了处理该异常的文件,程序将继续运行,如果没有编写,程序将停止运行,并显示traceback。
异常是使用try-except代码块来处理的。try-except代码块让Python执行指定的操作,并且告诉Python出现异常时,要如何处理。
3.1处理ZeroDivisionError异常
当用一个数除以0时,就会触发该异常。
3.2使用try-except代码块
当你认为程序可能会出现错误时,可以使用try-except代码块来处理可能引发的异常。
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide by zero!")
3.3使用异常避免程序崩溃
发生错误时,如果程序还没有运行完,妥善的处理错误尤为重要,这影响到你程序之后的运行。
print("Give me two numbers, and I will divide them!")
print("Enter 'q' to quit.")
while True:
first_number = input("\nFirst number")
if first_number == 'q':
break
second_number = input("\nSecond number")
if second_number == 'q':
break
answer = int(first_number)/int(second_number)
print(answer)
上段代码中,就未设置异常处理,当second_number输入0时,程序就会崩溃。所以要进行异常处理。
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("\nFirst number")
if first_number == 'q':
break
second_number = input("\nSecond number")
if second_number == 'q':
break
try:
answer = int(first_number)/int(second_number)
except ZeroDivisionError:
print("You can't divide by 0")
else:
print(answer)
try-except-else代码块工作原理如下,try中执行相关代码,如果出现异常执行except中代码,如果未发生异常,执行else中的代码。
3.5处理FileNotFoundError异常
使用文件时,一种常见的错误就是找不到文件。对于这种错误,我们也可以使用 try-except-else代码块进行异常处理。
filename = 'alice.txt'
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {contents} is not exist!")
本例在调用函数open()时,第二个是给参数encoding指定了值,在系统默认的编码与要读取文件的编码不一致时,必须要这样做。另外,使用了变量f来表示文件对象,这是一个常见的做法。
3.6分析文本
你可以分析包含整本书的文本文件,当然你还可以分析其它的文件,本文以此为例。
filename = 'chapter_10/alice.txt'
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {filename} is not exist!")
else:
# 计算文本中有多少单词
words = contents.split()
num_words = len(words)
print(num_words)
上段代码中,我们使用了方法split(),它能根据字符串创建一个单词的列表。该方法以空格为分隔符将字符串分割成多个部分,并将这些部分都储存到一个列表中。
3.7使用多个文件
当要读取多个文件中的信息时,我们可以把文件名做成一个列表,利用for循环依次读取其中的信息,并进行处理。当眼,我们也可以把计算单词的数量的代码写成一个函数,方便调用。
def count_words(filename):
"""计算一个文件中有多少单词"""
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
print(f"Sorry, the file {filename} is not exist!")
else:
"""计算文本中有多少单词"""
words = contents.split()
num_words = len(words)
print(f"{filename} has about {num_words} words")
filenames = ['chapter_10/alice.txt', 'chapter_10/siddhartha.txt', 'chapter_10/moby_dick.txt', 'chapter_10/little_women.txt']
for filename in filenames:
count_words(filename)
3.8静默失败
在上段代码中,我们告诉用户有一个文件找不到。但是并非每次都要告知用户出现了异常,有时候我们希望程序在遇到异常时保持静默,就像没遇到一样继续正常运行。这时,我们要用到pass语句。
def count_words(filename):
"""计算一个文件中有多少单词"""
try:
with open(filename, encoding='utf-8') as f:
contents = f.read()
except FileNotFoundError:
pass
else:
"""计算文本中有多少单词"""
words = contents.split()
num_words = len(words)
print(f"{filename} has about {num_words} words")
filenames = ['chapter_10/alice.txt', 'chapter_10/siddhartha.txt', 'chapter_10/moby_dick.txt', 'chapter_10/little_women.txt']
for filename in filenames:
count_words(filename)
当遇到异常时,会执行pass语句,即发生异常后,什么也不会发生,程序会继续正常运行。用户不会看到任何有关异常的信息。
当然,我们要根据用户的需要以及自身的需求,合理的决定要报告哪些信息。
4.存储数据
我们在要求用户输入一些数据后,有时需要存储这些数据,这时就要用到json模块,它能让你将数据结构存储到文件中,并在程序运行时再次加载数据。
4.1使用json.dump()和json.load()方法
下面将写两个简单的例子来存储和导入文件中的数据。
#写入json数据
import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as f:
json.dump(numbers, f)
#导入数据
import json
filename = 'numbers.json'
with open(filename) as f:
numbers = json.load(f)
print(numbers)
上面的代码中,导入了json模块,在将数据存储到文件中时,文件名的后缀要改成.json格式,表示你要以json形式存储数据。然后,调用了方法json.dump(),第一个参数是要存储的数据,第二个参数是你要将数据写入到那个文件中。在将数据导入到Python中时,同样先是导入json模块,然后指定一个要导入数据的文件,在使用json.load(打开文件时指定的别名)将文件中的数据导入,在赋值给一个变量即可。
4.2保存和读取用户生成的数据
使用json来保护用户生成的数据是很有效果的。下面是一个例子。
import json
username = input("What's youe name?")
filename = 'username.json'
with open(filename, 'w') as f:
json.dump(username, f)
print(f"We'll remember you,{username}!")
with open(filename) as f:
username = json.load(f)
print(f"Welcome back, {username}!")
当然,上段代码有许多瑕疵,下面进行改进,运用了try-except-else代码块。
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 ,{username}!")
else:
print(f"Welcome back, {username}!")