Python 文件和异常
1、从文件中读取数据:
1.1、读取整个文件:
-
每当需要分析或修改存储在文件中的信息时,读取文件都很有用,对数据分析应用程序来说尤其如此。
-
首先再当前目录中创建一个.txt结尾的文本文件,内如如下:
3.1415926535 8979323846 2643383279
-
再.py文件中输入:
with open('./test.txt') as file_obj: # 当前目录名字test.txt文件 contents = file_obj.read() print(contents) # 输出结果如下: 3.1415926535 8979323846 2643383279
-
函数open()
,要以任何方式使用文件——哪怕仅仅是打印其内容,都得先打开 文件,这样才能访问它函数open()接受一个参数:要打开的文件的名称。
- Python在
当前执行的文件所在的目录中查找指定的文件
- 函数open()
返回一个表示文件的对象
。在这里,open(‘test.txt’)返回一个表示文件test.txt 的对象
- 将这个
对象存储在我们将在后面使用的变量中。
-
关键字with 在不再需要访问文件后将其关闭
。- 到我们调用了
open() ,但没有调用close()
;你也可以调用open() 和close() 来打开和关闭文件
,但这样做时,如果程序存在bug,导致close() 语句未执行,文件将不会关闭
- 到我们调用了
-
我们使用
方法read()读取这个文件的全部内容
,并将其作为一个长长的字符串存储在变量contents
中.
-
1.2、文件路径:
-
要让
Python打开不与程序文件位于同一个目录中的文件,需要提供文件路径 ,它让Python到系统的特定位置去查找。
-
由于文件夹text_files位于文件夹python_work中,因此可使用
相对文件路径来打开该文件夹中的文件
-
在Linux和OSX中可以这样编写代码:
with open('text_files/filename.txt') as file_object:
-
在Windows系统中,在文件路径中使用
反斜杠(\ )而不是斜杠(/ )
:with open('text_files\filename.txt') as file_object:
-
-
还可以将文件在计算机中的准确位置告诉Python,这样就不用关心当前运行的程序存储在什么地方了。
这称为绝对文件路径
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt' with open(file_path) as file_object:
-
注意 Windows系统有时能够正确地解读文件路径中的斜杠。如果你使用的是Windows系统,且结果不符合预期,请确保在文件路径中使用的是反斜杠。
1.3、逐行读取:
-
读取文件时,常常需要检查其中的每一行:你可能要在文件中查找特定的信息,或者要以某种方式修改文件中的文本
file_name = './test.txt' with open(file_name) as file_obj: for line in file_obj: print(line) # 输出结果如下: 3.1415926535 8979323846 2643383279
- 我们将要读取的文件的名称存储在
变量file_name 中,这是使用文件时一种常见的做法
- 调用
open() 后,将一个表示文件及其内容的对象存储到了变量file_object 中
- 这里也使用了
关键字with
,让Python负责妥善地打开
和关闭文件
- 我们将要读取的文件的名称存储在
-
发现打印结果每行多出一个空行,
因为read() 到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。
-
要删除多出来的空行,可在print 语句中使用rstrip()
file_name = './test.txt' with open(file_name) as file_obj: for line in file_obj: print(line.rstrip()) # 输出结果如下: 3.1415926535 8979323846 2643383279
1.4、创建一个包含文件各行内容的列表:
-
使用关键字with 时,open() 返回的文件对象只在with 代码块内可用
-
如果要在with 代码块外访问文件的内容,可在
with代码块内将文件的各行存储在一个列表中
,并
在with代码块外使用该列表:file_name = './test.txt' with open(file_name) as file_obj: contents = file_obj.readlines() print(contents) for item in contents: print(item.rstrip()) # 输出内容如下: ['3.1415926535\n', ' 8979323846\n', ' 2643383279'] 3.1415926535 8979323846 2643383279
方法readlines() 从文件中读取每一行,并将其存储在一个列表中
1.5、使用文件的内容:
-
将文件读取到内存中后,就可以以任何方式使用这些数据
file_name = './test.txt' with open(file_name) as file_obj: contents = file_obj.readlines() print(contents) pi_string = '' for item in contents: pi_string += item.rstrip() print(pi_string) print(len(pi_string)) # 输出结果如下: ['3.1415926535\n', ' 8979323846\n', ' 2643383279'] 3.1415926535 8979323846 2643383279 34
首先打开文件,并将其中的所有行都存储在一个列表中
contents- 我们创建了一个变量——
pi_string
,用于存储圆周率的值 - 一个循环将各行都加入pi_string ,并删除每行末尾的换行符
-
为了删除两边的空格, 可以使用strip():
file_name = './test.txt' with open(file_name) as file_obj: contents = file_obj.readlines() print(contents) pi_string = '' for item in contents: pi_string += item.strip() print(pi_string) print(len(pi_string)) # 输出结果如下: ['3.1415926535\n', ' 8979323846\n', ' 2643383279'] 3.141592653589793238462643383279 32
-
注意:读取文本文件时,Python将其中的所有文本都解读为字符串。如果你读取的是数字,并要将其作为数值使用,就必须使用函数int() 将其转换为整数,或使用函数float() 将其转换为浮点数。
2、写入文件:
保存数据的最简单的方式之一是将其写入到文件中
。通过将输出写入文件,即便关闭包含程序输出的终端窗口,这些输出也依然存在
2.1、写入空文件:
-
将文本写入文件,你在调用open() 时需要提供另一个实参
file_name = './test.txt' with open(file_name, 'w') as file_obj: file_obj.write('I love Python') # 将test.txt文件打开会发现 I love Python # 已经写入进去了
- 调用
open() 时提供了两个实参
:第一个实参也是要打开的文件的名称
第二个实参('w' )告诉Python,我们要以写入模式 打开这个文件
- 打开文件时,可指定
读取模式 ('r' )
、写入模式 ('w' )
、附加模式 ('a' )
或让你能够读取和写入文件的模式('r+' )
。- 如果你
省略了模式实参
,Python将以默认的只读模式打开文件
。 - 如果你要
写入的文件不存在
,函数open() 将自动创建它
- 以
写入('w' )模式打开文件时千万要小心,因为如果指定的文件已经存在,Python将在返回文件对象前清空该文件。
- 如果你
- 我们使用
文件对象的方法write() 将一个字符串写入文件
- 调用
-
注意:Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str() 将其转换为字符串格式。
2.2、写入多行:
-
函数write() 不会在你写入的文本末尾添加换行符,因此如果你写入多行时没有指定换行符
file_name = './test.txt' with open(file_name, 'a+') as file_obj: file_obj.write('I love Python') file_obj.write('I love you') # 打开test.txt文件会发现 I love PythonI love you # 发现两行内容挤在一起了
-
要让每个字符串都单独占一行,需要在write() 语句中包含换行符:
file_name = './test.txt' with open(file_name, 'w') as file_obj: file_obj.write('I love Python\n') file_obj.write('I love you') # 打开test.txt 文件会发现 I love Python I love you # 跟我们预想的是一样的结果
2.3、附加到文件:
-
如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件。
-
附加模式打开文件时,Python不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾
-
如果指定的文件不存在,Python将为你创建一个空文件。
file_name = './test.txt' with open(file_name, 'a') as file_obj: file_obj.write('I love Python\n') file_obj.write('I love java\n') file_obj.write('I love you') # 打开test.txt文件的时候,里面已经有一段内容了 里面已经有一段内容了 I love Python I love java I love you
- 我们
打开文件时指定了实参'a'
,以便将内容附加到文件末尾,而不是覆盖文件原来的内容
- 我们
3、异常:
Python使用被称为异常的特殊对象来管理程序执行期间发生的错误
- 每当发生让Python不知所措的错误时,它都会创建一个异常对象
- 如果你编写了
处理该异常的代码,程序将继续运行
;如果你未对异常进行处理,程序将停止,并显示一个traceback,其中包含有关异常的报告
异常是使用try-except 代码块处理的。
- try-except 代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。使用了try-except 代码块时,即便出现异常,程序也继续运行:显示你编写的友好的错误消息,而不是令用户迷惑的traceback。
3.1、处理ZeroDivisionError 异常:
-
下面来看一种导致Python引发异常的简单错误。你可能知道不能将一个数字除以0
print(6/0) # 会报错 Traceback (most recent call last): File "C:/Users/lh9/PycharmProjects/request/my_test01.py", line 996, in <module> print(6/0) ZeroDivisionError: integer division or modulo by zero
- 在上述traceback中,
指出错误ZeroDivisionError:
是一个异常对象。 - Python无法按你的要求做时,就会创建这种对象。在这种情况下,Python将停止运行程序,并指出引发了哪种异常,而我们可根据这些信息对程序进行修改。
- 在上述traceback中,
3.2、使用try-except代码块:
-
当你认为可能发生了错误时,可编写一个try-except 代码块来处理可能引发的异常
try: print(6/0) except ZeroDivisionError: print('0不能被用做除数') # 输出结果就是 0不能被用做除数
如果try 代码块中的代码运行起来没有问题
,Python将跳过except 代码块
;- 如果
try 代码块中的代码导致了错误
,Python将查找这样的except 代码块,并运行其中的代码,即其中指定的错误与引发的错误相同
3.3、else代码块:
-
通过将可能引发错误的代码放在try-except 代码块中,可提高这个程序抵御错误的能力。
-
错误是执行除法运算的代码行导致的,因此我们需要将它放到try-except 代码块中。
-
这个示例还包含一个
else 代码块
;依赖于try 代码块成功执行的代码都应放到else 代码块中
while True: First = input('First number:') if First == 'q': break Second = input('\nSecond number:') try: answer = int(First) / int(Second) except ZeroDivisionError: print('0不能是被除数') else: print('成功输出') print(answer)
- Python尝试执行try 代码块中的代码;
- 只有可能引发异常的代码才需要放在try 语句中。
- 有时候,有一些仅在try 代码块成功执行时才需要运行的代码;
- 这些代码应放在else 代码块中。
- except 代码块告诉Python,如果它尝试运行try 代码块中的代码时引发了指定的异常,该怎么办。
- Python尝试执行try 代码块中的代码;
3.4、处理FileNotFoundError 异常:
-
使用文件时,一种常见的问题是找不到文件
: -
你要查找的文件可能在其他地方、文件名可能不正确或者这个文件根本就不存在。
-
对于所有这些情形,都可使用try-except 代码块以直观的方式进行处理。
filename = 'alice.txt' with open(filename) as f_obj: contents = f_obj.read()
-
python 无法读取不存在的文件,因此它引发一个异常:
Traceback (most recent call last): File "alice.py", line 3, in <module> with open(filename) as f_obj: FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
-
在上述traceback中,最后一行报告了FileNotFoundError 异常,这是Python找不到要打开的文件时创建的异常
-
这个
错误是函数open() 导致的
,因此要处理这个错误,必须将try 语句放在包含open() 的代码行之前:
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) # 最终结果输出如下: Sorry, the file alice.txt does not exist.
-
3.5、失败时一声不吭:
-
但并非每次捕获到异常时都需要告诉用户,有时候你希望程序在发生异常时一声不吭,就像什么都没有发生一样继续运行。
-
要让程序在失败时一声不吭,可像通常那样编写try 代码块,但在except 代码块中明确地告诉Python什么都不要做。
-
Python有一个pass 语句,可在代码块中使用它来让Python什么都不要做
:try: print(6/0) except ZeroDivisionError: pass print('Except 抛出的异常什么都没有, 使用了pass语句')
-
pass 语句还充当了占位符,它提醒你在程序的某个地方什么都没有做,并且以后也许要在这里做些什么。
4、存储数据:
模块json 让你能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据
你还可以使用json 在Python程序之间分享数据。
- 更重要的是,
json数据格式并非Python专用的,这让你能够将以JSON格式存储的数据与使用其他编程语言的人分享
4.1、使用json.dump()和json.load():
-
函数json.dump() 接受两个实参:要存储的数据以及可用于存储数据的文件对象。
import json numbers = [2, 3, 5, 7, 11, 13] file_name = 'numbers.json' with open(file_name, 'w') as f_obj: json.dump(numbers, f_obj) # 打开nubers.json的文件 内容如下: [2, 3, 5, 7, 11, 13]
- 我们先导入模块json ,再创建一个数字列表,指定了要将该数字列表存储到其中的文件的名称.
- 通常使用文件扩展名.json来指出文件存储的数据为JSON格式
- 我们使用函数json.dump() 将数字列表存储到文件numbers.json中。
-
使用json.load() 将这个列表读取到内存中
:import json numbers = [2, 3, 5, 7, 11, 13] file_name = 'numbers.json' with open(file_name) as f_obj: numbers = json.load(f_obj) print(numbers) # 输出结果如下: [2, 3, 5, 7, 11, 13]
- 我们使用函数json.load() 加载存储在numbers.json中的信息,并将其存储到变量numbers 中。
- 最后,我们打印恢复的数字列表,看看它是否与number_writer.py中创建的数字列表相同