Python学习笔记之文件与异常

Python学习笔记:文件与异常:

一:Python如何获取文件数据?

在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象。
系统中的文件分为两大类:字符文件和二进制文件。用记事本直接操作的文件就是字符文件,也叫文本文件;而图片、语音等属于二进制文件。Python可以操作这两种类型的文件,这里主要介绍如何处理文本文件。
Python处理文件的步骤包括打开、读写、关闭。首先要以读文件的模式打开一个文件对象,使用Python内置的open()函数传入文件名和其他参数。open()函数的常用方法是接收两个参数,即文件名(file)和模式(mode),如以下代码:

openfile,mode='r')

完整的语法格式如下:

open(file,mode='r',buffering=-1,encoding=None,errors=None,newline=None,closefd=True,opener=None)

其中参数的含义如下:
(1):file:必需,文件路径(相对或绝对路径)。如果是Linux环境,路径一般表示为’./data/file_name’;如果是windows环境,一般表示为’.\data\file_name’。因反斜杠在Python中被视为转义字符,所以为确保路径正确,应以原字符串的方式指定路径,即在开头的单引号前加上r。
(2)mode:可选,文件打开模式。
(3)buffering:可选,设置缓冲。
(4)encoding:可选,一般使用utf8.
(5)errors:可选,报错级别。
(6)newline:可选,区分换行符,如\n,,\r\n等。
(7)closefd:可选,传入的file参数类型。
(8)opener:可选,传入的file参数类型。
用open()函数打开文件的具体代码如下:

myfile=open(r"D:\data\hello.txt",'r')
contents=myfile.read()
print(contents)
myfile.close()

结果:

Python,java
PyTorch,TensorFlow,Keras

open()方法用来打开文件,里面的参数是文件路径和文件名。open()方法的返回值是一个文件对象(或称为文件句柄),也就是上面代码中的myfile变量,对该文件的所有操作都通过myfile完成。如果文件打开成功,调用read()方法可以一次性读取文件的全部内容,python会把内容读到内存。close()方法是文件对象提供的成员方法,用来关闭磁盘中的文件。整个过程就好比从一个房间中取东西,文件名就是房间号,首先用open()开门,其次取出东西,最后用close()关门。
操作系统将文件的操作划分了很多权限。

二:基本的文件操作

对文件的常用操作包括读取文件和写入文件。读取文件又可以根据文件的大小选择不同的读取方式,如按字节读取、逐行读取、读取整个文件等方式。

2.1:读取文件

打开文件后,读取文件使用read()方法。一个文本文件由多行字符串组成,二一行字符串又由多个字符组成,read(size)方法是以字节为单位读取文件内容,比如read(1)就是从当前文件指针位置开始,读取1个字节的内容。如果read()括号中没有数字或数字是负数,则读取整个文件的内容。
2.1.1:按字节读取
下面的代码每次从文件中读取固定的1个字节。每次读完后,文件指针会指向下一个字节的位置,就好比用瓢从水缸中舀水,每次都舀出相同的水量。

myfile=open(r"D:\data\hello.txt",'r')
token=myfile.read(1)
print(token)  #p
token=myfile.read(1)
print(token)  #y
token=myfile.read(2)
print(token)  #th
myfile.close()

2.1.2:读取整个文件
不指定read()括号中的参数,会读取整个文件的内容。

#读取整个文件
myfile=open(r"D:\data\hello.txt",'r')
token=myfile.read()
print(token)
myfile.close()

2.2:使用with语句读取文件:

Python语言为了避免忘记关闭文件,提供了with关键字来自动关闭文件。

#使用with语句读取文件
myfile=open(r"D:\data\hello.txt",'r') as myfile:
    print(myfile.read())

结果:

Python,java
PyTorch,TensorFlow,Keras

2.3:逐行读取文件

使用read()方法要么读取整个文件,要么读取固定字节数,总归不太方便。文本文件都是由多行字符串组成的,Python也可以使用readline()方法逐行读取文件。
2.3.1:逐行读取文件内容并打印

#逐行读取文件内容并打印
with open(r".\data\stu.csv")as myfiles:
    for line in myfiles:
        print(line)

结果:

no,name,age,gender

01,李康,15,M

02,张平,14,F

03,刘畅,16,M

2.3.2:去掉空行
从上面的打印结果可以看出,行之间多了空行。是疑问在文件中,每行的末尾都有一个不可见的换行符(如\n),print语句会加上这个换行符。要去掉这些空行,只需在print中使用rstrip()或strip()即可。

#逐行读取文件内容并打印,并去除空行
with open(r".\data\stu.csv")as myfiles:
    for line in myfiles:
        print(line.strip())

结果如下:

no,name,age,gender
01,李康,15,M
02,张平,14,F
03,刘畅,16,M

2.3.3:使用readline()可以每次读取一行

#使用readline()可以每次读取一行
with open(r".\data\stu.csv")as myfiles:
    line1=myfiles.readline()
    print(line1.strip())

运行:

no,name,age,gender

2.4:读取文件中的所有内容

使用readline()方法虽然可以一次读一行,但仍不够方便。
2.4.1:使用readlines()读取文件中的所有内容
Python还提供了readlines()方法,可以一次性把文件中的所有行都读出来,放入一个列表中。

#使用readlines()读取文件的所有内容
with open(r".\data\stu.csv")as myfiles:
    lists=myfiles.readlines()
    print(type(lists))
    for line in lists:
        print(line.strip())

结果:

<class 'list'>
no,name,age,gender
01,李康,15,M
02,张平,14,F
03,刘畅,16,M

2.4.2:定义Stu类并处理文件中每列的数据
下面将定义一个Stu类,该类实现利用readlines()函数返回的列表来处理每行的每列数据,并打印每列的属性值。

# 定义Stu类
class Stu:
    def __init__(self, no, name, age, gender):
        self.no = no
        self.name = name
        self.age = age
        self.gender = gender

    def debug(self):
        print("学号:{},姓名:{},年龄:{},性别:{}".format(self.no, self.name, self.age, self.gender))
# 处理文件中的每列数据
with open(r".\data\stu.csv")as myfiles:
    for line in myfiles.readlines():
        line = line.strip()
        # 不取第一行列名
        if (line[0] != 'n'):
            lst = line.split(',')
            stu = Stu(lst[0], lst[1], lst[2], lst[3])
            stu.debug()

运行结果如下:

学号:01,姓名:李康,年龄:15,性别:M
学号:02,姓名:张平,年龄:14,性别:F
学号:03,姓名:刘畅,年龄:16,性别:M

上面的这3种读文件的方法,都是从文件头开始读,直到遇到文件结束符(EOF)为止.这种读取方式叫顺序读取。但如果一个文件很大,而想读出其中的一小部分内容,可以采取随机读取方式,使用seek()或tell()方法,有兴趣的话可以参考相关文档资料。

2.5:写入文件

write(str)方法把str字符串写入文件,返回值是str字符串的长度。写文件前要先使用追加或写入模式打开文件。

with open(r'.\data\newfile','a') as myfile:
    myfile.write("hello,Python")

上面代码中的文件名为newfile,如果该文件不存在将自动创建。写入的方式是"a",即追加的方式,如果newfile文件存在,将往里追加记录,没有指定扩展名。但写入的是字符串,仍然是一个文本文件,可以使用记事本查看。write方法写入的字符串最后不会加上回车\n。
如果要把多行内容写入文件,可以每次每行都调用write方法,Python也提供了writelines(seq)方法一次性写入多行内容。seq参数是一个列表。

with open(r'.\data\newfile','w') as myfile:
    seq1=["第一行\n","第二行\n"]
    seq2=("第三行\n","第四行\n")
    myfile.writelines(seq1)
    myfile.writelines(seq2)
# 使用readlines()读取文件的所有内容
with open(r".\data\newfile")as myfiles:
    lists = myfiles.readlines()
    print(type(lists))
    for line in lists:
        print(line.strip())

运行结果:

<class 'list'>
第一行
第二行
第三行
第四行

以’w’模式写入文件时,如果文件已存在,会直接覆盖(相当于删掉后新写入一个文件)上面写入文件的字符串要加入回车键,否则即使调用多次writelines()方法,Python执行时也不会自动去加上回车。

2.6:中文乱码处理

open函数中有一个涉及字符集编码的参数encoding,Windows环境下的缺省字符集为GBK,比如前文中的newfile文件,若生成该文件时没有指明encoding,则系统采用GBK字符集。
可以用记事本的方式打开文件,然后选择’另存为‘选项,在‘另存为’界面的最后一栏有个编码框,那里就显示了当前文件的字符集。
默认请款报告下,Windows记事本的默认编码时ANSI(汉字表示积为GBK编码)。如果采用utf-8字符集生成文件,代码如下:

#采用utf-8字符集生成文件
with open(r'\data\newfile-utf8','w',encoding='utf-8') as myfile:
    seq1 = ["第一行\n", "第二行\n"]
    seq2 = ("第三行\n", "第四行\n")
    myfile.writelines(seq1)
    myfile.writelines(seq2)

注:必须用UTF-8方式打开,否则将乱码并报错。

3:目录操作

在先行的操作系统中,除了文件以外还包含有目录。文件目录被当作一种特殊类型的文件。
在Python中操作目录比操作文件简单一些。

3.1:OS简介

操作系统中的文件和目录,可以使用Python内置的OS模块,操作文件和目录的函数一部分放在OS模块中,另一部分放在os.path模块中。Os模块的主要方法如下:

方法含义
os.path.curdir返回当前程序的运行目录
os.path.abspath(p)返回文件对象的绝对路径
os.path.exists(p)判断文件或目录是否存在
os.path.isflie(p)判断文件对象是否时文件
os.path.isdir(p)判断文件对象是否是目录
os.path.join(p1,p2)拼接两个字符串
os.makedirs(p)创建多级目录
os.mkdir(p)创建目录
os.unlink(p)删除文件
os.rmdir(p)删除空目录

在使用os模块前要先引入 import os。

3.2:查看环境变量

利用os模块可以查看环境变量,操作系统中定义的环境变量全部保存在os.version这个变量中。

import os
#查看环境变量
print(os.environ)

4:异常处理

4.1:如何使程序更可靠?

程序员二点目的是写出能运行且不出错的程序,代码的健壮性和稳定性是衡量一个软件好坏的重要指标,大多数高级语言都提供了异常处理机制来确保代码的建筑行。Python的异常处理语法简单且功能实用,非常重要!

4.2:捕获异常

异常处理有两个关键字,即try和except。这两个关键字把程序分成两个代码块,try中放置程序正常运行的代码,except中是处理程序出错后的代码,鳍语句结构如下:

try<语句>      #运行别的代码
except<异常类型>
<语句>      #如果在try部分引发了'异常类型'的异常
[except <异常类型>,<数据>:
<语句>      #如果引发了'异常类型'的异常,则获得附加的数据]
[else:
<语句>      #如果没有异常发生]
[finally:
<语句>      #无论代码执行是否成功,都该执行语句]

try…except代码执行过程类似于if…else,但后者仅限于可以预知的错误,二except用来捕获隐藏的 错误。以下代码演示除数为0的异常。

#捕获异常
try:
    num1=10
    num2=0
    print(num1/num2)
except:
    print("除法运行错误,请检查数值")

结果:

除法运行错误,请检查数值

在进行文件操作时,也会出现各种异常情况,同样适用try…except语法格式。以下代码中要打开的文件并不存在,程序捕捉到这种异常后,会进入except模块。

try:
    myfile= open("test.txt")
    myfile.read()
    myfile.close()
except:
    print("处理文件出错")

运行结果:

处理文件出错

4.3:捕获多种异常

Python中定义的异常类型有很多种,针对不同类型的异常可以做区别处理,常见的几种类型如下:

异常类名含义
AttributeError对象缺少属性
IOError输入/输出操作失败
ImportError导入模块/对象失败
KeyError集合中缺少键值错误
NameError未生明或初始化变量
OSError操作系统错误
StopIteration迭代器没有更多的值
ZeroDivisionError除数为0或用0取模
Exception常规异常的基类

捕获多种异常的语法格式如下:

try:
  #正常执行代码行a
  #正常执行代码行b
  #... ...
except 异常类名1 as 变量名1:
  #处理异常1的代码块
except 异常类名2 as 变量名2:
  #处理异常2的代码块
except 异常类名3 as 变量名3:
   #处理异常3的代码块

把上一节的两种异常代码合并处理如下:

def demo():
    try:
        num1=10
        num2=0
        print(num1/num2)
    except ZeroDivisionError as e:
        print("除法运行错误",e)
    try:
        with open("test.txt") as myfile:
            myfile.read()
    except FileNotFoundError as e:
        print("处理文件出错",e)
demo()

运行结果如下:

除法运行错误 division by zero
处理文件出错 [Errno 2] No such file or directory: 'test.txt'

多个except并列,try中的代码最先遇到哪个异常种类,就会进入对应的except代码块,而忽略其他的异常种类。except…as后面的变量名e是为该异常类创建的实例,可以得到具体的异常信息。

4.4:捕获所有异常:

有那么多的异常种类,如果每个都捕获,那么代码写起来就太冗长了。Python的每个常规异常类行被定义成了一个类,这些类都有一个共同的父类,即Exception类。在不需要区分异常类型的情况下,把所有异常都归入Exception类也是通用的做法。

#捕获所有异常
import sys
try:
    with open('myfile.txt') as files:
        s =files.readline()
except IOError as err:
    print("I/O eror:{0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except:
    print("Unexpected error:",sys.exc_info()[0])
    raise

结果:

I/O eror:[Errno 2] No such file or directory: 'myfile.txt'

另外需要注意,如果多个except并列出现,要把Exception基类放在最下面,否则会出现某个异常种类捕捉不到的额情况。
以下代码就是错误的:

def demo():
  try:
    with open("test.txt") as myfile:
        myfile.read()
   
  except Exception as e:
    print("程序运行异常", e)
  except IOError as e:
    print("IO异常", e)
demo()
#程序运行异常[Errno 2]No such file or directory:'test.txt'

4.5:清理操作

异常处理中还有一个关键字是finally,finally代码块放在所有except代码的后面,无论是否执行了异常代码,finally中的代码都会被执行。

try:
    num1 = 10
    num2 = 0
    print(num1 / num2)
except Exception as e:
    print("程序运行异常", e)
finally:
    print("程序运行结束")
#程序运行结果
#程序运行异常 division by zero
#程序运行结束

finally关键字只能出现一次,里面的代码主要完成清理工作,比如关闭文件、关闭数据库链接、记录运行日志等。下面把关闭文件放在finally中。

#把关闭文件放在finally中
myfile = open(r".\data\stu.csv")
try:
  print(myfile.read(1))
except Exception as e:
  print("程序运行异常", e)
finally:
  myfile.close()

由于try、except、finally分属三个代码块,因此myfile变量需要定义在外面,以便在代码块中可以引用。

4.6:try/else/finally/return之间的关系

如果finally遇到return,finally是必然要执行的。finally中的return语句拥有最高的优先级输出。
如下代码:

def demo():
  
  try:
    myfile = open(r".\data\stu.csv")
    print(myfile.read(18))
    return 10
  except Exception as e:
    print("程序运行异常", e)
  else:
    print('没有错误')
  finally:
    myfile.close()
    print("文件已关闭")
    return 100


demo()


#程序运行结果
#no,name,age,gender
#文件已关闭
#100

为什么else部分的代码不执行呢?
因为,try部分有个return 10,而我们的目标是不出错直接return,那么else部分的内容自然就不执行了。
之所以返回的是100而不是10,是因为finally拥有最高的return权限。

小结:

文件和数据库在信息系统中一般被划分为硬件。
掌握异常处理的概念和用法是一名Python程序员的必备技能,所设计的有try/except/finally 3个关键字,以及常用的异常类的类名。不只是操作文件和数据库,正常的编码过程中,都要在适当的地方采用异常处理方式,才能变现出健壮的代码!

Soles on my shoes are worn the knees on my jeans are torn
鞋底磨穿,裤子磨破
Sweat coming through my shirt keep pushin’ even though it hurts
汗如雨下,即使受伤,也勇往直前
Chasing what I know it’s true there’s nothing that I would not do
追寻正确目标,我无所不能
When everyone around me drops I’m never gonna ever stop
当我身边的人一个个倒下,我也决不退缩
I won’t waste another minute no I won’t
我绝不浪费一分一秒,绝对不会
I’m a man on a mission
我肩负使命,肩负重任
I’m a man on a mission
我肩负使命,肩负重任
I don’t need no permission
我所向披靡,势不可挡
I’m a man on a mission take it up now take it up now
我肩负使命,肩负重任,立刻行动
I ain’t waiting and wishing take it up now take it up now
我绝不等待,从不祈梼,立刻行动
Oh I got that ambition take it up now take it up
我雄心勃勃,立刻行动
I’m a man on a mission
我肩负使命,肩负重任
When you look into my eyes you know you gonna see that fire
当你直视我的双眼,你会看到熊熊火焰
If you’re standing in my way it ain’t gonna be your day
如果你阻挡了我的去路,你必然难逃厄运
Bleed until I own this dream build it like you’ve never seen
流血成河,直到我拥有这个梦想建立它就像你从来没有见过
Even at the mountain top I’m never gonna ever stop
即使站在山峰之巅,我也决不退缩
I won’t wait another minute no I won’t
我绝不浪费一分一秒,绝对不会
I’m a man on a mission
我肩负使命,肩负重任
Man on a Mission–Oh The Larceny

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值