Python文件和异常

it2025-10-10  1

1. 从文件中读取数据

文本文件可以存储的数据量多得难以置信。要分析或者修改存储在文本文件中的信息时,都需要读取文件。可以一次性读取文件的全部内容,也可以每次一行的方式逐步读取。

1.1 读取整个文件

先创建一个文件,它包含精确到小数点后30位的圆周率值,且在小数点后10位出都换行: 下面的程序打开并读取这个文件,再将其内容显示到屏幕上:

with open('pi_digits.txt') as file_object: content = file_object.read() print(content)

输出:

3.1415926535 8979232846 2643383279

要以任何方式使用文件,都得先打开文件,这样才能访问它。函数open()接受一个参数:要打开的文件的名称。Python在当前执行的文件所在的目录中查找指定的文件。函数open()返回一个表示文件的对象。在这里,函数open(‘pi_digits.txt’)返回一个表示文件pi_digits.txt的对象;Python将这个对象存储在我们后面使用的变量中。

关键字with在不再需要访问文件时将其关闭。在这个程序中,我们调用了open(),但是没有调用close()。可以调用open()和close()来打开和关闭文件,但是这样做,如果程序存在bug,导致close()语句未执行,文件将不会关闭。这看起来虽然微不足道,但未妥善地关闭文件可能会导致数据丢失或者受损。如果在程序中过早的调用close(),你会发现需要使用文件时它已关闭,会导致更多的错误。并非在任何情况下都能轻松的确定文件关闭的恰当时机,但是通过使用with,可以让Python确定:你只管打开文件,并在需要时使用它,Pytohn自动会在何时的时候将其关闭。

相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。因为read()到达文件末尾时返回一个空字符串,而将这个空字符串显示出来就是一个空行。可以使用rstrip()来删除这个多余的空行:

with open('pi_digits.txt') as file_object: content = file_object.read() print(content.rstrip())

1.2 文件路径

with open(文件路径) as file_object:

当文件与程序文件在同一文件夹中时,可以使用相对路径。例如,程序文件存储在文件夹python_work中,在python_work中,有一名为text_files的文件夹,用于存储程序操作的文本文件。 在Linux和OS X中,可以这样编写代码:

with open('text_files/filename.txt') as file_object:

使用绝对路径,就不用了关心当前运行的程序文件存储在什么地方了。但是一般绝对路径都比较长,所以先将绝对路径存储在一个变量中,再将该变量传递给open(): 在Linux和OS X中:

file_path = '/home/ehmatthes/other_files/text_files/ filename .txt' with open(file_path) as file_object:

在Windows操作系统中:

file_path = 'C:\Users\ehmatthes\other_files\text_files\ filename .txt' with open(file_path) as file_object:

1.3 逐行读取

要以每次一行的方式检查文件,可以使用for循环进行遍历:

file_name = 'pi_digits.txt' with open(file_name) as file_object: for line in file_object: print(line.rstrip())

输出:

3.1415926535 8979232846 2643383279

1.4 创建一个包含文件各行内容的列表

使用关键字with时,open()返回的文件对象只能在with代码块内可用。如果要在with代码块外访问文件的内容,可在with代码块内将文件的各行存储在一个列表中。

file_name = 'pi_digits.txt' with open(file_name) as file_object: lines = file_object.readlines() for line in lines: print(line.rstrip())

方法readlines()从文件中读取每一行,并将其存储在一个列表中。

1.5 使用文件的内容

将文件读取到内存后,就可以以任何方式使用这些数据了。

file_name = 'pi_digits.txt' with open(file_name) as file_object: lines = file_object.readlines() pi_string = '' for line in lines: pi_string += line.strip() print(pi_string) print(len(pi_string))

2. 写入文件

保存数据最简单的方式之一就是将其写入到文件中。

2.1 写入空文件

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

file_name = 'test.txt' with open(file_name, 'w') as file_object: file_object.write("I Love Python!")

调用open()时提供了两个实参,第一个实参是要打开的文件的名称;第二个实参(‘w’)是要以写入模式打开1这个文件。还有其他的模式:

读取模式('r') read 写入模式('w') write 附加模式('a') append 读取和写入模式('r+'

如果省略了模式实参,Python将以默认的只读模式打开。如果要写入的文件不存在,函数open()将自动创建它。以写入模式(‘w’)打开文件时,如果指定的文件已经存在,Python将在返回文件对象前清空该文件。

Python只能将字符串写入到文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。

file_name = 'test.txt' with open(file_name, 'w') as file_object: file_object.write(str(20200202))

2.2 写入多行

函数write()不会在你写入的文本末尾添加换行符,所以在写入多行时应在行尾添加换行符。

file_name = 'test.txt' with open(file_name, 'w') as file_object: file_object.write(str(20200202) + "\n") file_object.write("Hello!")

2.3 附加到文件

如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件。以附加模式打开文件时,Python不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件的末尾。如果指定的文件不存在,Python将会为你创建一个空文件。

file_name = 'message.txt' with open(file_name, 'a') as file_object: file_object.write("First line") file_object.write("second line")

3. 异常

Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Pytohn不知道所措的错误时,它都会创建一个异常对象。如果编写了处理该异常的代码,程序将继续运行;如果你未对异常进行处理,程序将停止,并显示一个traceback,其中包含有关异常的报告。 异常是使用 try-except代码处理的。try-except代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。使用了try-except代码块时,即便出现了异常,程序也能继续运行。

3.1 处理ZeroDivisionError异常

0不可以被当做除数,下面我们让一个数除以0:

print(5/0)

输出:

raceback (most recent call last): File "division.py", line 1, in <module> print(5/0) ZeroDivisionError: division by zero

在上述traceback中,第6行指出的错误ZeroDivisionError是一个异常对象。Python程序出现错误时,就会创建这种对象。在这种情况下,Python将停止运行程序,并指出引发了哪种异常,我们可以根据这些信息对程序进行修改。

3.2 使用try-except代码块

当你认为可能发生错误时,可以编写一个try-except代码块来处理异常。

try: print(5/0) except: print("You can not divide by zero !")

将导致错误的代码行print(5/0)放在一个try代码块中。如果try代码块中的代码运行没有问题,就会跳过except代码块;如果try代码块中的代码导致了错误,Python将会查找except代码块,并运行其中的代码,即其中指定的错误与引发的错误相同。

3.3 使用异常避免崩溃

发生错误时,如果程序还有工作没有完成,妥善的处理错误尤其重要。下面来创建一个只执行除法运算的简单计算器:

print("Give me two numbers,and I will divide them.") print("Enter 'q' to quit.") while True: num1 = input("Please input a number1: ") if num1 == 'q': break num2 = input("Please input a number2: ") if num2 == 'q': break answer = int(num1)/int(num2) print(result)

运行输出:

Give me two numbers,and I will divide them. Enter 'q' to quit. Please input a number1: 8 Please input a number2: 0 Traceback (most recent call last): File "test.py", line 40, in <module> answer = int(num1)/int(num2) ZeroDivisionError: division by zero

这个程序没有采取任何的错误处理措施,让它执行除数为0的除法运算时,它将崩溃。如果用户怀有恶意,会通过traceback获悉你不希望他知道的信息。比如程序文件的名称,部分不能正确运行的代码,训练有素的攻击者可以通过这些信息发起攻击。

3.4 else代码块

将可能引发错误的代码块放入try-except代码块中,可以提高这个程序低于错误的能力。错误是执行除法运算的代码行导致的,因此我们需要将它放在try-except代码块中。这个示例还包括了else代码块;依赖于try代码块成功执行后的代码应该都放在else代码块中:

print("Give me two numbers,and I will divide them.") print("Enter 'q' to quit.") while True: num1 = input("Please input a number1: ") if num1 == 'q': break num2 = input("Please input a number2: ") if num2 == 'q': break try: answer = int(num1)/int(num2) except ZeroDivisionError: print("You can not divide by zero !") else: print(answer)

运行输出:

Give me two numbers,and I will divide them. Enter 'q' to quit. Please input a number1: 1 Please input a number2: 0 You can not divide by zero !

3.5 处理FileNotFoundError异常

使用程序时,一种常见的问题是找不到文件。下面我们来尝试读取一个不存在的文件:

file_name = 'alice.txt' with open(file_name) as f_object: content = f_object.read()

输出:

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'

Python找不到要打开的文件时就会创建异常,这个异常是函数open()导致的,要处理这个异常,就要将open()函数放在try代码块内:

file_name = 'alice.txt' try: with open(file_name) as f_object: content = f_object.read() except: message = "Sorry,the file " + file_name + " not exists." print(message)

3.6 分析文本

方法split()可以根据一个字符串创建一个单词列表:

message = 'who have touched their lives.' list = message.split() print(list)

方法split()以空格为分隔符将字符串拆分成多个部分,再将这些部分存储到一个列表中。结果是一个包含字符串中所有单词的列表。我们可以对整篇文章使用split()方法,计算得到的列表包含多少个元素,从而确定整篇文章大致包含多少个单词:

file_name = 'article.txt' try: with open(file_name,'r',encoding='UTF-8') as file_object: content = file_object.read() except: msg = "Sorry,the file " + file_name + " is not exists." print(msg) else: words = content.split() new_words = len(words) print("The file " + file_name + " has about " + str(new_words) + " words.")

输出:

The file article.txt has about 303 words.

3.7 使用多个文件

下面多分析几本书,将程序的大部分代码都移动一个名为count_words()函数中:

def count_words(file_name): """统计文章词数""" try: with open(file_name,'r',encoding='UTF-8') as file_object: content = file_object.read() except: msg = "Sorry,the file " + file_name + " is not exists." print(msg) else: words = content.split() new_words = len(words) print("The file " + file_name + " has about " + str(new_words) + " words.") file_names = ['article.txt', 'message.txt'] for file_name in file_names: count_words(file_name)

输出:

The file article.txt has about 303 words. The file message.txt has about 188 words.

3.8 失败时一声不吭

并非每次捕获异常都要告诉用户,有时候希望程序在发生异常时一声不吭。Python有一个pass语句,可在代码块中使用它来让Python什么都不要做:

def count_words(filename): """统建一个文件大概有多少个字符""" try: --snip-- except FileNotFoundError: pass else: --snip-- filenames = ['alice.txt','siddhartha.txt','moby_dick.txt','little_women.txt'] for filename in filenames: count_words(filename)

4. 存储数据

程序经常需要用户输入某种信息并将其存储到列表或者字典等数据结构中。当用户关闭程序时,你几乎总要保存他们提供的信息。一种简单的方式是使用模块json来存储数据。

模块json能够让你将简单的Python数据结构存储到文件中,在程序再次运行时加载该文件中的数据。JSON数据格式不只是Python专用的,可与其他编程语言的人分享以JSON格式存储的数据。

4.1 使用json.dump()和json.load()

下面编写一个存储一组数字的程序,在编写一个将这组数字读取到内存中的程序。第一个程序将使用json.dump()来存储数字,第二个程序将使用json.load()。

import json numbers = [1,3,5,7,9] file_name = "numbers.json" with open(file_name,'w') as file_object: json.dump(numbers,file_object)

使用json.load()将这个列表读物到内存中:

with open(file_name) as file_object: message = json.load(file_object) print(message)

输出:

[1, 3, 5, 7, 9]

4.2 保存和读取用户生成的数据

用户首次运行程序时被提示输入自己的姓名,再次运行程序时就记住他了。

import json username = input("Please input your name: ") file_name = "usernames.json" with open(file_name,'w') as file_object: json.dump(username,file_object) print("We will remeber you when you come back," + username + "!")

再编写一个程序,向其名字被存储的用户发出问候:

import json filename = 'username.json' with open(filename) as f_obj: username = json.load(f_obj) print("Welcome back," + username + "!")

下面将两个程序合并到一个程序(remember_me.py)中。这个程序中,我们将尝试从username.json中获取用户名,因此我们首先编写一个尝试恢复用户名的try代码块。如果文件不存在,就可以在except代码块中提示输入用户名,并将其输入到username.json中。

import json file_name = 'usernames.json' try: with open(file_name) as file_object: username = json.load(file_object) except FileNotFoundError: username = input("Please input your name: ") with open(file_name,'w') as file_object: json.dump(username,file_object) print("We will remeber you when you come back, " + username + "!") else: print("Welcome " + username)

4.3 重构

你经常会遇到这样的情况:代码能够正确运行,但是可以做出进一步改进–将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。重构让代码更清晰、更易于理解、更容易扩展。

本博客是博主阅读《Python编程:从入门到实践》一书所做的笔记,博客中代码与理论来源于该书。

最新回复(0)