文件、异常和存储数据

  • 一、文件
  • 1、从文件中读取数据
  • 2、写入文件
  • 二、异常
  • 1、try-except代码块
  • 2、处理FileNotFoundError 异常
  • 2、失败时一声不吭
  • 三、存储数据
  • 1、json模块
  • 2、保存和读取用户生成的数据
  • 3、重构


一、文件

1、从文件中读取数据

我们首先简单看一下下面会使用到的文件

’pi_digits.txt’

python程序设计第七章数据文件和异常处理课后答案 python第七章文件与异常答案_后端


’pi_million_digits’

python程序设计第七章数据文件和异常处理课后答案 python第七章文件与异常答案_python_02


从当前文件目录件中读取数据:

with open('pi_digits.txt') as file_object:
    """
    关键字with 在不再需要访问文件后将其关闭(不需要使用close())
    """
    contents = file_object.read()  # 为read() 到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行
    print(contents.rstrip())  # rstrip()方法删除字符串末尾的空白
  • 关键字with在不再需要访问文件后将其关闭(即不需要调用close()即可关闭文件)。
  • read() 到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一 个空行。要删除多出来的空行,可在print语句中使用rstrip()

从其他文件目录件中读取数据:

# 相对路径
with open('text_files/filename.txt') as file_object:
    ...
    ...
    ...

# 绝对路径
file_path = '/home/ehmatthes/other_files/text_files/filename.txt' 
with open(file_path) as file_object:
    ...
    ...
    ...
  • 相对路径:指当前文件目录下的子文件或文件目录。
  • 绝对路径:指文件的实际具体位置。

注意:Python里的文件目录分隔符是" / “,而不是” \ "。

逐行读取文件:

file_name = 'pi_digits.txt'

with open(file_name) as file_object:
    for line in file_object:     # 因为在这个文件中,每行的末尾都有一个看不见的换行符,
        print(line.rstrip())     # 而print 语句也会加上一个换行符,因此每行末尾都有两个换行符:一个来自文件,另一 个来自print语句。

在with代码块外使用open返回的对象(语法上是只可以在with里用的):

file_path = 'text_files/pi_digits.txt'  # 相对路径

with open(file_path) as file_object:
    lines = file_object.readlines()  # 方法readlines() 从文件中读取每一行,并将其存储在一个列表中;
                                     # 接下来,该列表被存储到变量lines 中;在with 代码块外,我们依然可以使用这个变量。
for line in lines:
    print(line.rstrip())
  • 方法readlines() 从文件中读取每一行,并将其存储在一个列表中;接下来,该列表被存储到变量lines中;这样,在with代码块外,我们依然可以使用这个变量。

使用文件中的内容:
将圆周率的前50位打在一行:

# #使用文件的内容
file_path1 = 'E:/Learn_code/Python/learnPython/text_files/pi_million_digits.txt'  # 绝对路径

with open(file_path1) as file_object:
    lines = file_object.readlines()

    pi_string = ''
    for line in lines:
        pi_string += line.strip()  # 每行左边的空格,为删除这些空格,可使用strip()

print(pi_string[:52] + "...")  # 打印到小数点后50位
print(len(pi_string))

Test:圆周率中包含你的生日吗
下述代码中的pi_string为上面代码得到的。

# #小测试(圆周率中包含你的生日吗)
birthday = input("Enter you birthday,in the form like mmdd:")
if birthday in pi_string:
    print("Your birthday appears in the first million digits of pi!")
else:
    print("our birthday does not appear in the first million digits of pi.")

2、写入文件

调用open() 时提供了两个实参。第一个实参是要打开的文件的名称;第二个实参(‘w’ )告诉Python,我们要以写入模式打开这个文件。
打开文件时,可指定:

  • 读取模式 (‘r’ )
  • 写入模式 (‘w’ )、
  • 附加模式 (‘a’ )
  • 读取和写入文件的模式(‘r+’ )。

如果你省略了模式实参,Python将以默认的只读模式打开文件。

如果你要写入的文件不存在,函数open() 将自动创建它。
然而,以写入(‘w’ )模式打开文件时千万要小心,因为如果指定的文件已经存在,Python将在返回文件对象前清空该文件。

注:python只能将字符串写入文本文件。要存储数值数据,需要使用str()
示例:

filename = 'programming.txt'  # 没有该文件  所以python会新创建一个这么文件
with open(filename, 'w') as file_object:
    file_object.write("I love programming.")
    file_object.write("That's a great thing.\n")  # 并不会另起一行写在文件中,另起一行需要换行符
    file_object.write("I love creating new games.\n")

# 如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件
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")

示例结果:

python程序设计第七章数据文件和异常处理课后答案 python第七章文件与异常答案_json_03

二、异常

Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。

1、try-except代码块

代码块功能:

当你认为可能发生了错误时,可编写一个try-except 代码块来处理可能引发的异常。如果try 代码块中的代码运行起来没有问题,Python将跳过except 代码块;如果try代码块中的代码导致了错误,Python将查找这样的except代码块,并运行其中的代码,即其中指定的错误与引发的错误相同。

示例:

try:
    print(5/0)
except ZeroDivisionError:
    print("You cannot divided by 0!")

运行此代码块结果如下:

python程序设计第七章数据文件和异常处理课后答案 python第七章文件与异常答案_json_04


可以看出并不会引发错误,Python将跳过try里面的内容,执行except语句内容。

try-except-else 代码块:

发生错误时,如果程序还有工作没有完成,妥善地处理错误就尤其重要。这种情况经常会出现在要求用户提供输入的程序中;如果程序能够妥善地处理无效输入,就能再提示用 户提供有效输入,而不至于崩溃。

通过将可能引发错误的代码放在try-except-else代码块中,可提高这个程序抵御错误的能力。
示例:

print("Give me 2 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("Second number: ")
    try:
        answer = int(first_number) / int(second_number)
    except ZeroDivisionError:
        print("You cannot divided by 0!")
    else:
        print(answer)

结果如下:

python程序设计第七章数据文件和异常处理课后答案 python第七章文件与异常答案_json_05

2、处理FileNotFoundError 异常

文件名不存在、文件名或目录错误会引发FileNotFoundError错误。

eg: 打开一个不存在的文件:

# ##FileNotFoundError异常(文件名不存在或者文件名或目录错误)
filename = 'yb.txt'   # 一个不存在的文件

try:
    with open(filename) as file_object:
        contents1 = file_object.read()
except FileNotFoundError:
    print("Sorry,the file " + filename + " does not exist.")

结果如下:

python程序设计第七章数据文件和异常处理课后答案 python第七章文件与异常答案_后端_06

Test:分析文本(包含多少word)

#  ##分析文本
def count_words(internal_file_name):
    """计算一个文本文件大致包含多少单词"""
    try:
        with open(internal_file_name) as file_obj:
            contents2 = file_obj.read()
    except FileNotFoundError:
        print("Sorry,the file " + internal_file_name + " does not exist.")
    else:                    # 计算文件中大致包含多少单词
        words = contents2.split()
        num_words = len(words)
        print("The file " + internal_file_name + " has about " + str(num_words) +
              " words.")


file_names = ['text_files/text1.txt', 'text_files/text2.txt',
              'text_files/text3.txt', 'text_files/text4.txt']
for file_name in file_names:
    count_words(file_name)

其中,text1、2、3、4是4个文本文件,里面是词语数量不等的。

2、失败时一声不吭

有时候你希望程序在发生异常时一声不吭,就像什么都没有发生一样继续运行。 要让程序在失败时一声不吭,可像通常那样编写try 代码块,但在except 代码块中明确地告诉Python什么都不要做。在except语句中使用pass即可。

def count_words(filename):      """计算一个文件大致包含多少个单词"""
    try:
    --snip -      
    except FileNotFoundError:
    pass 
    else:          
    --snip -

三、存储数据

1、json模块

很多程序都要求用户输入某种信息,如让用户存储游戏首选项或提供要可视化的数据。不管专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中。用户关闭程序时,你几乎总是要保存他们提供的信息;一种简单的方式是使用模块json来存储数据。

使用json.dump()存储:

  • 函数json.dump() 接受两个实参:要存储的数据以及可用于存储数据的文件对象。

使用 json.load加载:

  • 函数json.loadd() 接受一个实参:存储数据的文件对象

存储和加载演示:

import json

# 存储
numbers_store = [1, 2, 3, 4, 5]

filename = 'numbers.json'
with open(filename, 'w') as f_obj:
    json.dump(numbers_store, f_obj)

# 加载
with open(filename) as f_obj:
    numbers_load = json.load(f_obj)

print(numbers_load)
  • 该代码将生成一个number.json文件,并在其中存储数组。最后加载该文件,将数组输出。
  • 通常使用文件扩展名 .json来指出文件存储的数据为JSON格式。

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

一个记住我的小程序:

# 如果以前存储了用户名就加载它
#  否则就提示用户输入用户名并存储它
filename = 'username.json'
try:
    with open(filename) as f_obj:
        username = json.load(f_obj)
except FileNotFoundError:
    username = input("What's 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 + "!")

3、重构

概念:

—将代码划分为一系列完成具体工作的函数。这样的过程被称为重构

使用函数完成上述’’‘记住我’’'的小程序,见下:

import json

def get_stored_username():
    """Get stored username if available."""
    filename = 'username.json'
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
        return None
    else:
        return username

def get_new_username():
    """Prompt for a 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():
    """Greet the user by name."""
    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()

注意:

上面在二.2讲解了FileNotFoundError :文件名不存在、文件名或目录错误会引发。但是,又在一.2写入文件的代码示例中,说不存在该文件时会自动创建一个。这两者并不矛盾,在能自动创建一个文件的前提,是需要使用 ‘w’ 模式,即写入模式才可以。否则就会引发FileNotFoundError错误。