python基础-文件和错误处理

7555次阅读 320人点赞 作者: WuBin 发布时间: 2025-02-12 10:59:03
扫码到手机查看

文件读取

读取整个文件

with open('demo_2.txt') as file_object:
    content = file_object.read()
    print(content)

open(‘要打开的文件路径’):如果向代码中那样传入名称,则会基于py脚本目录进行文件的查找,文件打开成功返回一个文件对象file_object;

with是在不需要访问文件后将其关闭。因为正常情况下调用了open就必须调用close。比如

filePath = 'demo_2.txt'
file = open(filePath, 'r') // 只读
filew = open('demo_w.txt', 'w') // 写入

words = file.read()
filew.write(words); // 将内容写入

print(words);
// 关闭两个文件
file.close()
filew.close()

但是这样做有个问题,当程序出现Bug,导致close未执行的时候,文件将不会关闭,而过早的调用close则会导致使用文件的时候它已经关闭了(无法访问)。而我们使用with,就可以让PY自动确定,在需要的时候使用它,并让PY在合适的时机自动关闭文件。

with语句是一种上下文管理器,它提供了一种非常方便的方式来管理资源,如文件操作、网络连接、数据库连接等。

with主要作用和使用场景体现在以下几个方面:

1. 确保资源的正确释放

在使用一些资源时,例如文件、网络连接或数据库连接,我们需要在使用完后正确地释放这些资源,以避免资源泄漏。传统的方式是使用try...finally语句,但使用with语句可以让代码更加简洁和安全。

# 传统的文件操作方式
try:
    file = open('test.txt', 'r')
    content = file.read()
    print(content)
finally:
    file.close()

# 使用 with 语句的文件操作方式
with open('test.txt', 'r') as file:
    content = file.read()
    print(content)

传统方式使用try...finally确保文件在操作完成后关闭,而使用with语句则更简洁,with语句会自动处理文件的关闭操作,即使在操作过程中出现异常,也能保证文件被正确关闭。

2. 自动管理上下文

with语句的执行过程涉及到上下文管理器协议,即对象需要实现__enter__()__exit__()方法。当执行with语句时,会调用对象的__enter__()方法,该方法的返回值会赋值给as后面的变量;当with语句块执行完毕或出现异常时,会调用对象的__exit__()方法,进行资源的清理工作。

class MyContextManager:
    def __enter__(self):
        print("进入上下文管理器")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("退出上下文管理器")
        if exc_type is not None:
            print(f"发生异常: {exc_type}, {exc_value}")
        return True

with MyContextManager() as my_obj:
    print("在上下文管理器内部执行操作")
    # 可以在这里模拟异常
    # raise ValueError("这是一个测试异常")

在上述示例中,MyContextManager类实现了上下文管理器协议,当执行with语句时,会依次调用__enter__()__exit__()方法。

3. 简化代码结构

使用with语句可以避免大量的try...finally嵌套,使代码更加清晰和易读,特别是在处理多个资源时,优势更加明显。比如多个资源管理:

# 同时打开两个文件进行操作
with open('file1.txt', 'r') as file1, open('file2.txt', 'w') as file2:
    content = file1.read()
    file2.write(content)

使用with语句同时管理两个文件的打开和关闭操作,代码简洁明了。

read

read()是读取文件中的全部内容,并将内容保存为字符串返回。但是read到达文件末尾时会返回一个空字符串,会导致显示出来就是一个空行,如果要删除末尾空行,就要使用rstrip()

print( content.rstrip() )

逐行读取

要以每次一行的方式检查文件,可以对文件对象使用for循环:

with open('demo_2.txt') as file_object:
    for line in file_object:
        if 'language' in line:
            print(line.rstrip())

加上rstrip()方法目的就是 因为逐行输出的时候,每行的末尾都会有个换行符,要消除这些空白行,就要使用rstrip()方法

创建一个包含文件各行内容的列表

使用with+open的时候,返回的文件对象只能在with代码块中可用,如果要在with之外使用文件内容,可以将逐行内容添加到一个列表中。

with open('demo_2.txt') as file_object:
    lines = file_object.readlines()

for line in lines:
    print(line)

readlines从文件中读取每一行,并将其存储在一个列表中,并返回这个列表。这样在with代码块外部,依然可以使用这个列表

读取文本文件的时候,会将所有文件内容都转化为字符串,如果内容是数字,那么就需要根据情况使用Int()转化为整数或者float()转化为浮点数。

文件写入

文件写入时,需要传入另一个参数,告诉PY你要写入打开的文件。

with open('write_demo.txt', 'w') as file_object:
    file_object.write('hello world!\n')

open('文件路径', ‘打开模式’):打开模式有3种:

'r': 默认,读取;'w': 写入;‘a’:附加模式;‘r+':让你能读取和写入文件的模式。

如果要写入的文件不存在,那么PY会自动创建它,而以'w'写入模式打开的文件,PY会在返回文件对象前清空该文件。

如果要将数值存储到文本文件种,必须使用str()转换为字符串形式。

写入多行

write()不会在写入的文本末尾加换行符,所以在使用.write的时候,需要主动加入换行符

with open('write_demo.txt', 'w') as file_object:
    file_object.write('hello world!\n')
    file_object.write('i miss you!\n')

附加内容

如果要给文件添加内容,而不是覆盖原有内容,就可以使用附加模式:'a',以附加模式打开文件时,PY不会再返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾。另外与w一样,文件不存在则新建一个文件。

with open('write_demo.txt', 'a') as file_object:
    file_object.write('and i wanna to see you')

异常

PY使用异常这个特殊对象来管理程序执行期间发生的错误,当遇到错误,PY会创建一个异常对象,并显示一个traceback。

异常使用try-except代码块进行处理。

比如,实现一个最简单的traceback:

print( 5 / 0)

报错:

ZeroDivisionError                         Traceback (most recent call last)
Cell In[5], line 1
----> 1 print( 5 / 0)

ZeroDivisionError: division by zero

ZeroDivisionError就是一个异常对象,当PY无法按照你的要求做时,就会创建这种对象。

try:
    print(5/0)
except ZeroDivisionError:
    print('你不能除以0')

如果try-except后面还有其他代码,则程序会接着运行。

while True:
    first_num = input('\n请输入第一个数字:')
    if first_num == 'q':
        break
    second_num = input('请输入第二个数字:')
    try:
        answer = int(first_num) / int(second_num)
    except ZeroDivisionError:
        print('除数不能为0')  // 5/0走这里
    else:
        print(answer) // 6/2 走这里 

将可能引发错误的代码放在try-except中,而else则代表try代码块成功执行之后的部分放在else中。

except ZeroDivisionError告诉PY如果出现ZeroDivisionError错误该怎么办。

处理FileNotFoundError

使用文件常遇到的错误是找不到文件。

with open('nopath.txt', 'r') as file_object:
    content = file_object.read()

// 错误
FileNotFoundError                         Traceback (most recent call last)
Cell In[7], line 1
----> 1 with open('nopath.txt', 'r') as file_object:
      2     content = file_object.read()

所以要优化报错:

try:
    with open('nopath.txt', 'r') as file_object:
        content = file_object.read()
except FileNotFoundError:
    print('文件不存在')
这里要注意:try-except要写在with去读文件的外面。
try:
    with open('demo_2.txt') as file_object:
        contents = file_object.read()
except FileNotFoundError:
    print('文件不存在')
else:
    words = contents.split()
    print( len(words) )

上面例子实现了一个查看文件中有多少个单词。

split() 以空格分隔字符串,并将拆分的(单词)部分存为一个列表。

len(列表) 则返回一个列表的长度。

遇到问题 一声不吭

并非每个捕获异常都需要告诉用户,有时需要像什么都没有发生一样继续运行。这时候就要使用PY的pass语句,让它告诉py什么都不要做。

try:
    with open('nopath.txt') as file_object:
        contents = file_object.read()
except FileNotFoundError:
    pass
else:
    words = contents.split()
    print( len(words) )

使用pass当遇到异常的时候,什么都不会发生,也不会有任何的输出。pass语句还充当了占位符。

存储数据

json.dump

json.dump:用于存储数据,接受两个参数,json.dump(‘要存储的数据’, ‘用于存储的文件对象)

import json
nums = list(range(1,6)) // 创建一个1-6的列表

filename = 'numbers.json'

with open(filename, 'w') as file_object:
    json.dump(nums, file_object)
使用json.dump以及json.load需要先引入json模块
  • range(1, 6)函数会生成一个从 1 开始(包含 1)到 6 结束(不包含 6)的整数序列,即1, 2, 3, 4, 5
  • list()函数将这个range对象转换为一个列表,所以arr最终是[1, 2, 3, 4, 5]

注意:json.dump写入文件要对文件使用'w'写入模式。

json.load

filename = 'numbers.json'
with open(filename) as file_object:
    nums = json.load(file_object)

print(nums)

使用json.load可以将文件内容加载到内存中。

综合案例

filename = 'username.json'
try:
    # 先从文件中读取 如果文件不存在那么就让用户输入并创建
    with open(filename) as file_read:
        username = json.load(file_read)
except FileNotFoundError:
    # 如果用户名文件不存在 那么询问
    username = input('你叫什么名字\n')
    with open(filename, 'w') as file_write:
        json.dump(username, file_write)
        print('我们记住你的名字了:' + username)
else:
    print('欢迎回来' + username)

上面例子是执行脚本,当脚本不存在到时候 进入except,引导用户输入,并保存用户名。如果文件存在则进入else,输出用户名。

这里在敲代码时候遇到几个问题:

1、脚本文件名不可以是json.py

AttributeError: partially initialized module 'json' has no attribute 'dump' (most likely due to a circular import) 可以看出,问题出在循环导入上。当你把 Python 文件命名为 json.py 时,Python 在尝试导入 json 模块时,会优先导入你当前的 json.py 文件,而不是 Python 标准库中的 json 模块,这样就导致无法使用标准库 json 模块里的 dump 和 load 等方法。

所以不要起与py模块同名的脚本文件!

2、当无意中创建了空的username.json文件时,执行json.load会报错:

JSONDecodeError: Expecting value: line 1 column 1 (char 0)通常表示json.load()函数试图解析一个空的 JSON 文件或者文件内容不是有效的 JSON 格式。如果username.json文件为空,json.load()就会抛出JSONDecodeError异常,因为它期望文件中包含有效的 JSON 数据。

所以,保险起见,可以这么修改:

try:
    with open(filename, 'r') as file_object:
        # 先读取文件内容
        content = file_object.read()
        # 检查文件内容是否为空
        if content:
            username = json.loads(content)
        else:
            # 文件为空,执行与文件不存在时相同的操作
            username = input('你叫什么名字\n')
            with open(filename, 'w') as file:
                json.dump(username, file)
                print('我们记住你的名字了:' + username)

先执行一次file_object.read()判断json中有没有内容,有内容再执行json.load

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:open
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    10356次阅读 684人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    4871次阅读 366人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    14957次阅读 987人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    14220次阅读 548人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    13040次阅读 1055人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    17209次阅读 1382人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    15655次阅读 1269人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    30981次阅读 2437人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    26813次阅读 2062人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录