10 - 文件和异常处理

1.文件打开

open(name[, mode[, buffering]])
  • 打开一个文件,返回一个file类型的对象。如果文件打不开,抛出IOError。注意,想要打开一个文件,使用open函数比file函数好。
  • mode主要包括:
    • r:只读,默认方式
    • w:写入,覆盖原来内容
    • a:写入,在原来内容后面追加
    • b:打开二进制文件

使用示例:

input = open(r"c:\pybook\Scores.txt", "r")
input = open("c:\\pybook\\Scores.txt", "r")

注意二者的区别,在path前加 r 表示这是一个行字符串会让Python解释器将文件名中的反斜线理解为字面意思。如果没有 r ,那么需要转义。

  • buffering指的是文件所需的缓冲区大小。0表示无缓冲,1表示 line buffered,其它数字n表示缓冲大小为 n bytes。为负数或缺省表示使用系统默认大小。

  • 如果文件内容是 unicode 格式,那么可以用添加 encoding = ‘xxx’ 来将其转化成bytes形式,这样就不会出现乱码了。如:

    open(path, ‘r’, encoding= ‘utf-8’)

2.写入数据

_io.TextIOWrapper类:

  • read(number) 读取指定数量的字符,省略时默认返回全部剩余内容
  • readline() 返回下一行
  • readlines() 返回文件剩余行的列表
  • write(s) 向文件写入一个字符串
  • close() 关闭文件

3.判断文件是否存在

imort os.path
if os.path.isfile("Presidents.txt")
    print("Presidents.txt exists")

4.读数据

infile = open("Presidents.txt", "r")
print(infile.read())
infile.close()

infile = open("Presidents.txt", "r")
print(infile.readlines())
infile.close()

infile = open("Presidents.txt", "r")
print(infile.readline())
print(infile.readline())
print(infile.readline())
infile.close()

5.读取文件中的所有数据

当读到文件末尾时,readline返回”。

line = infile.readline()
while line != '':
    line = infile.readline()

Python 也支持for循环读取:

for line in infile:
    ...

6.从网站上获取数据

import urllib.request


def main():
    url = input("Enter a URL for a file:")
    infile = urllib.request.urlopen(url)
    s = infile.read().decode()

    counts = countsLetters(s.lower())

    for i in range(len(counts)):
        if counts[i] != 0:
            print(chr(ord('a') + i) + "appears" + str(counts[i]) +
                  ("time" if counts[i] == 1 else "times"))


def countsLetters(s):
    counts = 26 * [0]
    for ch in s:
        if ch.isalpha():
            counts[ord(ch) - ord('c')] += 1
    return counts

if __name__ == "__main__":
    main()

7.异常处理

异常处理使程序能够处理已成然后继续它的正常执行

try:
    ...
except <Exception>:
    ...

其工作方式如下:

  • 首先,try … except之间的语句被执行
  • 如果没有异常,跳过except字句。
  • 如果有异常,那么try的剩余部分将被跳过。
  • 当出现异常的时候,如果异常类型匹配关键字except之后的异常名,那么except之后的将被执行,然后跳过try字句中异常之后的语句,转而继续处理except之后的语句
  • 如果出现异常但是不匹配except之后的异常类型,那么这个异常将被传递给这个函数的调用者;如果让没有找到异常处理器,那么这是一个未被捕捉的异常,将导致程序终止显示错误信息。

多个except语句,带else和finally:

try:
    ...
except <ExceptType1>:
    <handler1>

except <ExceptType2>:
    <handler2>
except:
    <handlerExcept>
else:
    ...
finally:
    ...

其工作方式如下:

  • 当出现异常时,顺序检查各个except语句,如果有匹配的那就执行处理语句,其他except语句将会被忽略。
  • 如果未匹配任何except语句,那么就执行最后一个不带ExceptType的字句。
  • 一个try语句可以有一个可选的else字句,如果try块中没有异常抛出,将会执行else块
  • 一个try语句可以有一个可选的finally块,用来定义收尾动作,无论何时都会被执行

8. 抛出异常

异常来自哪里?异常如何产生?附属在异常上的信息包裹在一个对象中,异常产生自一个函数。当检测到一个错误时,用以下语法从一个异常类创建一个对象,并抛给这个函数的调用者。

raise ExceptionClass("Something is wrong")

其工作原理如下,当程序检测到传递给函数的一个参数与这个函数的合约冲突,这个程序将创建一个RuntimeError类的实例并将它抛出:

ex = RutimeError("Wrong argument")
raise ex

可简写成:

raise RuntimeError("Wrong argument")

现在你也可以在程序中自行抛出异常了,然后在调用的时候用 catch … exeption 语句捕捉

9.那么使用异常处理的好处是什么?

使用异常处理能够使函数给它的调用者抛出一个异常,调用者能够处理这个异常,如果没有这种能力,被调用者必须自己处理这个异常或者终止这个程序。

通常被调用者不知道如何处理一个错误,这对库函数来说是典型情况。 库函数可以检测到错误,但是只有调用者知道如何处理错误。异常处理的最重要优势在于将错误检测和错误处理分隔开来

许多库函数能够抛出多种异常,像ZeroDivisionError、TypeError、IndexError等等。

10.使用对象处理异常

如前所述,一个异常被包裹在一个对象中。为了抛出一个异常,需要首先创建一个异常对象,然后使用 raise 关键字将它抛出。

我们可以 在 except 字句中访问这个抛出的对象,可以使用下面的方法将 exception 对象赋给一个变量

try:    
    ...
except ExceptionType as ex:
    <handle>
    print("Execption: ", ex)

11.自定义异常

Python内置异常的层次结构图:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |         +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |         +-- UnicodeError
      |              +-- UnicodeDecodeError
      |              +-- UnicodeEncodeError
      |              +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
       +-- ImportWarning
       +-- UnicodeWarning
       +-- BytesWarning

BaseException是所有异常类的父类。所有的异常类都直接或间接地继承自BaseException类。Python提供了很多的异常类,也允许定义自己的异常类。

自定义异常类举例:

当用户输入的半径为负数的时候抛出异常:

class InvalidRadiusException(RuntimeError):
    def __init__(self, radius):
        super().__init__()
        self.radius = radius

圆的实现(在setRadius函数中抛出异常):

from GeometricObject import GeometricObject
from InvalidRadiusException import InvalidRadiusException 
import math

class Circle(GeometricObject):
    def __init__(self, radius):
        super().__init__()
        self.setRadius(radius)

    def getRadius(self):
        return self.__radius

    def setRadius(self, radius):
        if radius >= 0:
            self.__radius = radius
        else:
            raise InvalidRadiusException(radius)

    def getArea(self):
        return self.__radius * self.__radius * math.pi

    def getDiameter(self):
        return 2 * self.__radius

    def getPerimeter(self):
        return 2 * self.__radius * math.pi

    def printCircle(self):
        print(self.__str__(), "radius:", self.__radius)

测试函数(捕获并处理异常):

from CircleWithCustomException import Circle
from InvalidRadiusException import InvalidRadiusException 

try:
    c1 = Circle(5)
    print("c1's area is", c1.getArea())
    c2 = Circle(-5)
    print("c2's area is", c2.getArea())
    c3 = Circle(0)
    print("c3's area is", c3.getArea())
except InvalidRadiusException as ex:
    print("The radius", ex.radius, "is invalid")
except Exception:
    print("Something is wrong")

12.使用Picking进行二进制IO

可以向一个文件中写入字符串和数字,但是是否能够向文件中写入像列表这样的任何一个对象呢?

答案是肯定的。这需要二进制IO。

Python中有很多方法进行二进制IO,这里介绍使用 pick 模块中的 dump 和 load 函数进行二进制 IO。 Pick 模块使用强大的算法进行序列化和反序列化。

  • 序列化:指将一个对象转换为一个能够存储在一个文件中或者在网络上进行传输的 字节流 的过程。
  • 反序列化:指的是相反的过程,它是将从字节流中提取出对象的过程。

序列化/反序列化在Python中也称为 浸渍/去渍 或者 卸载/加载 对象。

卸载和加载对象:
import pickle

def main():
    # Open file for writing binary
    outfile = open("pickle.dat", "wb")
    pickle.dump(45, outfile)
    pickle.dump(56.6, outfile)
    pickle.dump("Programming is fun", outfile)
    pickle.dump([1, 2, 3, 4], outfile)
    outfile.close() # Close the output file

    # Open file for reading binary
    infile = open("pickle.dat", "rb")
    print(pickle.load(infile))
    print(pickle.load(infile))
    print(pickle.load(infile))
    print(pickle.load(infile))
    infile.close() # Close the input file

main() # Call the main function

要注意的几点:

  • 使用 wb 模式打开这个文件以二进制形式写入。
  • 使用 dump 方法将对象写入到文件中(将对象序列化成字节流写入)
  • 使用 load 方法来读取对象(读取一个字节流并将它们反序列化为一个对象)
检测文件末尾

如果不知道文件有多少内容,那么可以通过检测 EOFError异常,当抛出这个异常时,捕捉它并处理它以结束文件读取过程。

infile = open("numbers.dat", "rb")

end_of_file = False
while not end_of_file:
    try:
        print(pickle.load(infile), end = " ")
    except EOFError:
        end_of_file = True

infile.close() # Close the input file
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值