第八章 文件和异常

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():用于将数据读取到内存中

  1. 函数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(),这个函数只负责获取并存储新用户的用户名。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容

  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,737评论 0 10
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,168评论 0 3
  • 文件和异常 至此,已经掌握了编写组织有序而易于使用的程序所需的基本技能,该考虑让程序目标更明确、用途更大了。 本章...
    焰火青春阅读 410评论 0 1
  • 雪 雪一片一片的, 像一个个精灵。 在这寒冷冬夜, 带来快乐。 像一朵朵冰花, 绽放在天地之间。
    追凌大旗阅读 213评论 0 0
  • “念白,我在你楼下的花园里,你来一下。”王俊凯的电话总是那么简洁,不容反抗。 我迅速从21楼回到地...
    星零岁时记阅读 268评论 0 1