Python编程从入门到实践_第十章_文件和异常

本文详细介绍了Python中如何进行文件的读取和写入,包括读取整个文件、逐行读取、创建文件内容列表以及处理大型文件。同时,讲解了异常处理的基本概念,如`try-except`代码块的使用,以及如何处理`ZeroDivisionError`和`FileNotFoundError`异常。此外,还涉及了数据的存储,特别是使用`json`模块来保存和读取数据。
摘要由CSDN通过智能技术生成

第十章:文件和异常


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

注意:

  1. strip()rstrip()的区别。

  2. 读取文本文件时,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()

总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值