第五章 文件和异常

第五章 文件和异常

5.1 文件路径

Python将在当前执行的文件(即.py程序文件)所在的目录中查找文件。有时可能要打开不在程序文件所属目录中的文件。

要让Python打开不与程序文件位于同一个目录中的文件,需要提供文件路径 (相对文件路径、绝对文件路径)。

  • Windows操作系统
    在Windows系统中,在文件路径中使用反斜杠(\ )而不是斜杠(/ )。斜杠(/ )代表转义字符。

  • Linux操作系统
    在Linux系统中,使用斜杠(/ )。

  • 绝对路径
    绝对路径指的是文件在硬盘上真正的路径。

     c:\文件夹1\文件夹2\abc.txt 
    
  • 相对路径
    相对路径是指目标相对于当前文件的路径。

    1. ./ :代表目前所在的目录。
    2. …/ :代表上一层目录。
    3. 以 / 开头:代表根目录。

5.2 从文件中读取数据

要使用文本文件中的信息,首先需要将信息读取到内存中。为此,你可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取。

  • 函数 open()

    调用open()来打开一个文件,可以将文件分成两种类型:一种,是纯文本文件(使用utf-8等编码编写的文本文件),一种,是二进制文件(图片、mp3、ppt等这些文件)。
    函数 open() 返回 文件对象,通常的用法需要两个参数:

    open(filename, mode)  
    f = open('workfile', 'w')
    
    1. 第一个参数是一个含有文件名的字符串。第二个参数也是一个字符串,含有描述如何使用该文件的几个字符。

    2. mode 为 ‘r’或’rt’ 时表示只是读取纯文本文件;‘w’或’wt’ 表示只是写入纯文本文件(已经存在的同名文件将被删掉);‘a’或’at’ 表示打开文件进行追加纯文本文件,写入到文件中的任何数据将自动添加到末尾。 ‘rt+’ 表示打开纯文本文件进行读取和写入。mode 参数是可选的,默认为 ‘r’。

    3. 通常,文件以 文本 打开,这意味着,你从文件读出和向文件写入的字符串会被特定的编码方式(默认是UTF-8)编码。模式后面的 ‘b’ 以 二进制模式 打开文件:数据会以字节对象的形式读出和写入。

    4. 要读取文件内容,需要调用 f.read(size),该方法读取若干数量的数据并以字符串形式返回其内容,size 是可选的数值,指定字符串长度。如果指定size数值,每次调用read(size)时系统会记录当前读取位置,下一次读取都是从上次读取到位置开始读取的。

    5. 如果没有指定 size 或者指定为负数,就会读取并返回整个文件。

    6. 当文件大小为当前机器内存两倍时,就会产生内存泄漏问题。

    7. 如果到了文件末尾,f.read() 会返回一个空字符串。

    8. 相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。为何会多出这个空行呢?因为read() 到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删除多出来的空行,可在print 语句中使用rstrip() :这样输出与原始文件的内容完全相同。

    file_name = 'hello.txt'
    
    with open(file_name,'r') as file_obj:
        chunk = 10
        while True:
            content = file_obj.read(chunk)
            if not content:
                break
            else:
                print(content,end='')
    
    print('\n'+'-'*1000)
    #错误写法
    with open(file_name,'r') as file_obj:
        chunk = 10
        while file_obj.read(chunk):             #第一次调用read()
            print(file_obj.read(chunk),end='')         #打印的 会少一次read(chunk)
            #read 会记录每次读取后的位置 再次调用 会从当前位置继续向下读取
    
  • readline()函数

    f.readline() 从文件中读取单独一行,字符串结尾会自动加上一个换行符( \n ),只有当文件最后一行没有以换行符结尾时,这一操作才会被忽略。

    #readline()
    
    file_name = 'hello.txt'
    
    with open(file_name,'r') as file_obj:
        while True:
            content = file_obj.readline()
            if not content:
                break
            else:
                #print(content,end='')
                print(content.strip())
    

    你可以循环遍历文件对象来读取文件中的每一行。这是一种内存高效、快速,并且代码简介的方式:

    #readline() 2
    
    file_name = 'hello.txt'
    
    with open(file_name,'r') as file_obj:
        content = file_obj.readline()
    
    for i in content:
        print(i,end='')
    # i 为content 中的每一个字符,而不是每一行字符,使用end='' 将字符显示成一行。
          
    
  • readlines()函数

    如果你想把文件中的所有行读到一个列表中,你也可以使用 list(f) 或者 f.readlines()。

    ## readlines()
    
    file_name = 'hello.txt'
    
    with open(file_name,'r') as file_obj:
        content = file_obj.readlines()
    
    for i in content:
        print(i,end='')
    
    print('\n' + '-' * 1000)
    
    # 文件列表
    
    file_name = 'hello.txt'
    
    with open(file_name,'r') as file_obj:
        print(type(file_obj))
        for i in file_obj:
            print(i.strip())    ##默认多一个换行 使用strip消除
    
  • tell()函数和seek()函数

    • tell()函数
      tell() 返回一个整数,代表文件对象在文件中的指针位置,该数值计量了自文件开头到指针处的比特数。
      f.tell()  
      
    • seek()函数
      需要改变文件对象指针的话,使用 f.seek(offset,from_what)。指针在该操作中从指定的引用位置移动 offset 比特,引用位置由 from_what 参数指定。 from_what 值为 0 表示自文件起始处开始,1 表示自当前文件指针位置开始,2 表示自文件末尾开始。from_what 可以忽略,其默认值为零,此时从文件头开始。
      注意:当文件没有以二进制模式打开文件时,seek()函数只允许从文件头开始计算相对位置。否则将会报错。
        f = open('workfile', 'rb+')
        f.write(b'0123456789abcdef')
        16
        f.seek(5)     # Go to the 6th byte in the file
        5
        f.read(1)
        b'5'
        f.seek(-3, 2) # Go to the 3rd byte before the end
        13
        f.read(1)
        b'd'
      
  • close()函数
    当你使用完一个文件时,调用 f.close() 方法就可以关闭它并释放其占用的所有系统资源。 在调用 f.close() 方法后,试图再次使用文件对象将会自动失败。

      f.close()
    
  • 关键字 with
    关键字with 在不再需要访问文件后将其关闭。在这个程序中,注意到我们调用了open() ,但没有调用close() ;你也可以调用open() 和close() 来打开和关闭文件,但这样做时,如果程序存在bug,导致close() 语句未执行,文件将不会关闭。

    file_name = 'hello.txt'
    
    with open(file_name,'r') as file_obj:
        print(type(file_obj))
        for i in file_obj:
            print(i.strip())    ##默认多一个换行 使用strip消除
    

5.3 写入文件

  • 写入空文件
    要将文本写入文件,在调用open() 时提供另一个实参’w’,告诉Python你要写入打开的文件。

    file_name = 'new_text.txt'
    
    with open(file_name,'w') as file_obj:
        file_obj.write('I love programming.')
    
  • 写入多行
    函数write() 不会在你写入的文本末尾添加换行符,要添加”\n” 换行符。

    filename = 'programming.txt'
    with open(filename, 'w') as file_object:
        file_object.write("I love programming.\n")
        file_object.write("I love creating new games.\n")
    
  • 附加到文件
    如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式 打开文件。你以附加模式打开文件时,Python不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾。如果指定的文件不存在,Python将为你创建一个空文件。

    filename = 'programming.txt'
    
    with open(filename, 'a') as file_object: 
        file_object.write(" meaning in large datasets.\n")
        file_object.write("run in a browser.\n")
    
  • 打开文件的模式

    • 二进制文件

      1. rb:以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。
      2. wb:以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
      3. ab:以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
      4. rb+:以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
      5. wb+:以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
      6. ab+:以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

      注意:rb+和wb+ 都以二进制格式打开一个文件用于读写。但是在文件不存在的时候,wb+ 会自动创建新文件。

    • 纯文本文件

      1. r:以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
      2. w: 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
      3. a: 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
      4. r+: 打开一个文件用于读写。文件指针将会放在文件的开头。
      5. w+: 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
      6. a+: 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。

5.4 异常

Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Python不知所措的错误时,它都会创建一个异常对象。如果你编写了处理该异常的代码,程序将继续运行;如果你未对异常进行处理,程序将停止,并显示一个traceback,其中包含有关异常的报告。

异常是使用try-except 代码块处理的。try-except 代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。使用了try-except 代码块时,即便出现异常,程序也将继续运行。

  • 使用try-except 代码块

      try:
            代码块(可能出现错误的语句)
      except 异常类型 as 异常名:
            代码块(出现错误以后的处理方式)
      except 异常类型 as 异常名:
            代码块(出现错误以后的处理方式)
      except 异常类型 as 异常名:
            代码块(出现错误以后的处理方式)
      else:
            代码块(没出错时要执行的语句)    
      finally:
            代码块(该代码块总会执行)    
    

    try是必须的,else语句可以不存在,except和finally至少有一个。

    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.")
    
  • 异常的传播
    当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播。

    如果函数中没有对异常进行处理,则异常会继续向函数调用处传播。

    如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播。

    直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息。

    所有的异常对象都是从BaseException类中派生出来的。

     file_name = 'hello.txt'
        
     with open(file_name,'r') as file_obj:
         # print(file_obj.tell())
         # file_obj.seek(10,0)
         # print(file_obj.tell())
     try:
             file_obj.seek(-10,2)
             print(file_obj.tell())
     except BaseException:
             print("请以二进制文件模式打开")
    
  • 抛出异常

    我们可以使用raise语句自己触发异常。一旦执行了raise语句,raise后面的语句将不能执行。

    格式:raise 异常名称(‘异常描述’)。

    raise RuntimeError('testError')
    
    • 自定义异常
      python的异常分为两种。

      1. 内建异常,就是python自己定义的异常。

      2. 用户自定义异常
        在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值