第五章 文件和异常
5.1 文件路径
Python将在当前执行的文件(即.py程序文件)所在的目录中查找文件。有时可能要打开不在程序文件所属目录中的文件。
要让Python打开不与程序文件位于同一个目录中的文件,需要提供文件路径 (相对文件路径、绝对文件路径)。
-
Windows操作系统
在Windows系统中,在文件路径中使用反斜杠(\ )而不是斜杠(/ )。斜杠(/ )代表转义字符。 -
Linux操作系统
在Linux系统中,使用斜杠(/ )。 -
绝对路径
绝对路径指的是文件在硬盘上真正的路径。c:\文件夹1\文件夹2\abc.txt
-
相对路径
相对路径是指目标相对于当前文件的路径。- ./ :代表目前所在的目录。
- …/ :代表上一层目录。
- 以 / 开头:代表根目录。
5.2 从文件中读取数据
要使用文本文件中的信息,首先需要将信息读取到内存中。为此,你可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取。
-
函数 open()
调用open()来打开一个文件,可以将文件分成两种类型:一种,是纯文本文件(使用utf-8等编码编写的文本文件),一种,是二进制文件(图片、mp3、ppt等这些文件)。
函数 open() 返回 文件对象,通常的用法需要两个参数:open(filename, mode) f = open('workfile', 'w')
-
第一个参数是一个含有文件名的字符串。第二个参数也是一个字符串,含有描述如何使用该文件的几个字符。
-
mode 为 ‘r’或’rt’ 时表示只是读取纯文本文件;‘w’或’wt’ 表示只是写入纯文本文件(已经存在的同名文件将被删掉);‘a’或’at’ 表示打开文件进行追加纯文本文件,写入到文件中的任何数据将自动添加到末尾。 ‘rt+’ 表示打开纯文本文件进行读取和写入。mode 参数是可选的,默认为 ‘r’。
-
通常,文件以 文本 打开,这意味着,你从文件读出和向文件写入的字符串会被特定的编码方式(默认是UTF-8)编码。模式后面的 ‘b’ 以 二进制模式 打开文件:数据会以字节对象的形式读出和写入。
-
要读取文件内容,需要调用 f.read(size),该方法读取若干数量的数据并以字符串形式返回其内容,size 是可选的数值,指定字符串长度。如果指定size数值,每次调用read(size)时系统会记录当前读取位置,下一次读取都是从上次读取到位置开始读取的。
-
如果没有指定 size 或者指定为负数,就会读取并返回整个文件。
-
当文件大小为当前机器内存两倍时,就会产生内存泄漏问题。
-
如果到了文件末尾,f.read() 会返回一个空字符串。
-
相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。为何会多出这个空行呢?因为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'
- tell()函数
-
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")
-
打开文件的模式
-
二进制文件
- rb:以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。
- wb:以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
- ab:以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
- rb+:以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
- wb+:以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
- ab+:以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
注意:rb+和wb+ 都以二进制格式打开一个文件用于读写。但是在文件不存在的时候,wb+ 会自动创建新文件。
-
纯文本文件
- r:以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
- w: 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
- a: 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
- r+: 打开一个文件用于读写。文件指针将会放在文件的开头。
- w+: 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
- 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的异常分为两种。-
内建异常,就是python自己定义的异常。
-
用户自定义异常
-
-