携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情
文件和异常
在Python中实现文件的读写操作其实非常简单,通过Python内置的open函数,我们可以指定文件名、操作模式、编码信息等来获得操作文件的对象,接下来就可以对文件进行读写操作了。这里所说的操作模式是指要打开什么样的文件(字符文件还是二进制文件)以及做什么样的操作(读、写还是追加),具体的如下表所示。
| 操作模式 | 具体含义 |
|---|---|
| 'r' | 读取 (默认) |
| 'w' | 写入(会先截断之前的内容) |
| 'x' | 写入,如果文件已经存在会产生异常 |
| 'a' | 追加,将内容写入到已有文件的末尾 |
| 'b' | 二进制模式 |
| 't' | 文本模式(默认) |
| '+' | 更新(既可以读又可以写) |
根据应用程序的需要来设置操作模式。

文件读写
try except finally
fp = None # 文件描述符
try:
fp = open('致橡树.txt', 'r', encoding='utf-8')
print(fp.read())
except FileNotFoundError:
print('无法打开指定的文件!')
except LookupError:
print('指定了未知的编码!')
except UnicodeDecodeError:
print('读取文件时解码错误!')
finally:
if fp:
fp.close()
无法打开指定的文件!
with
在Python中,我们可以将那些在运行时可能会出现状况的代码放在try代码块中,
在try代码块的后面可以跟上一个或多个except来捕获可能出现的异常状况。
例如在上面读取文件的过程中,
文件找不到会引发FileNotFoundError,
指定了未知的编码会引发LookupError,
而如果读取文件时无法按指定方式解码会引发UnicodeDecodeError,
我们在try后面跟上了三个except分别处理这三种不同的异常状况。
最后我们使用finally代码块来关闭打开的文件,
释放掉程序中获取的外部资源,
由于finally块的代码不论程序正常还是异常都会执行到
(甚至是调用了sys模块的exit函数退出Python环境,finally块都会被执行,因为exit函数实质上是引发了SystemExit异常),
因此我们通常把finally块称为“总是执行代码块”,
它最适合用来做释放外部资源的操作。
如果不愿意在finally代码块中关闭文件对象释放资源,
也可以使用上下文语法,
通过with关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源,
代码如下所示。
try:
with open('未知.db', 'r', encoding = 'utf-8') as fp:
print(fp.read())
except FileNotFoundError:
print('无法打开指定的文件!')
except LookupError:
print('指定了未知的编码!')
except UnicodeDecodeError:
print('读取文件时解码错误!')
finally:
if fp:
print("文件没关闭")
else:
print('文件已关闭')
无法打开指定的文件!
文件已关闭
文件还可以通过列表遍历
with open('有名.db', 'r', encoding = 'utf-8') as lines:
lst = list(lines)
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
Input In [19], in <cell line: 1>()
----> 1 with open('有名.db', 'r', encoding = 'utf-8') as lines:
2 lst = list(lines)
FileNotFoundError: [Errno 2] No such file or directory: '有名.db'
文件的写
要将文本信息写入文件文件也非常简单,在使用open函数时指定好文件名并将文件模式设置为'w'即可。
注意如果需要对文件内容进行追加式写入,应该将模式设置为'a'。
如果要写入的文件不存在会自动创建文件而不是引发异常。
下面的例子演示了如何将1-9999之间的素数分别写入三个文件中(1-99之间的素数保存在a.txt中,
100-999之间的素数保存在b.txt中,1000-9999之间的素数保存在c.txt中)
def is_prime(n:int)->bool:
"""判断素数的函数"""
assert n > 0
factor = 2
while factor <= (n // factor):
if n % factor == 0:
return False
factor = factor + 1
return True if n != 1 else False
filenames = ('a.txt', 'b.txt', 'c.txt') # 元组
fs_list = []
try:
for filename in filenames:
fs_list.append(open(filename, 'w', encoding='utf-8'))
for number in range(1, 10000):
if is_prime(number):
if number < 100:
fs_list[0].write(str(number) + '\n')
elif number < 1000:
fs_list[1].write(str(number) + '\n')
else:
fs_list[2].write(str(number) + '\n')
except IOError as ex:
print(ex)
print('写文件时发生错误!')
finally:
for fs in fs_list:
fs.close()
print('操作完成!')
with open('a.txt', 'r', encoding = 'utf-8') as fp:
print(list(fp))
操作完成!
['2\n', '3\n', '5\n', '7\n', '11\n', '13\n', '17\n', '19\n', '23\n', '29\n', '31\n', '37\n', '41\n', '43\n', '47\n', '53\n', '59\n', '61\n', '67\n', '71\n', '73\n', '79\n', '83\n', '89\n', '97\n']
读写JSON文件
通过上面的讲解,我们已经知道如何将文本数据和二进制数据保存到文件中,
那么这里还有一个问题,
如果希望把一个列表或者一个字典中的数据保存到文件中又该怎么做呢?
答案是将数据以JSON格式进行保存。JSON是“JavaScript Object Notation”的缩写,
它本来是JavaScript语言中创建对象的一种字面量语法,现在已经被广泛的应用于跨平台跨语言的数据交换,
原因很简单,因为JSON也是纯文本,任何系统任何编程语言处理纯文本都是没有问题的
。目前JSON基本上已经取代了XML作为异构系统间交换数据的事实标准。
关于JSON的知识,更多的可以参考JSON的官方网站,从这个网站也可以了解到每种语言处理JSON数据格式可以
使用的工具或三方库,下面是一个JSON的简单例子。
import json
def main():
mydict = {
'name': '骆昊',
'age': 38,
'qq': 957658,
'friends': ['王大锤', '白元芳'],
'cars': [
{'brand': 'BYD', 'max_speed': 180},
{'brand': 'Audi', 'max_speed': 280},
{'brand': 'Benz', 'max_speed': 320}
]
}
try:
with open('data.json', 'w', encoding='utf-8') as fs:
json.dump(mydict, fs)
except IOError as e:
print(e)
print('保存数据完成!')
if __name__ == '__main__':
main()
保存数据完成!
json模块主要有四个比较重要的函数,分别是:
dump - 将Python对象按照JSON格式序列化到文件中
dumps - 将Python对象处理成JSON格式的字符串
load - 将文件中的JSON数据反序列化成对象
loads - 将字符串的内容反序列化成Python对象
这里出现了两个概念,
一个叫序列化,一个叫反序列化。
自由的百科全书维基百科上对这两个概念是这样解释的:
“序列化(serialization)在计算机科学的数据处理中,
是指将数据结构或对象状态转换为可以存储或传输的形式,这样在需要的时候能够恢复到原先的状态,
而且通过序列化的数据重新获取字节时,可以利用这些字节来产生原始对象的副本(拷贝)。
与这个过程相反的动作,即从一系列字节中提取数据结构的操作,就是反序列化(deserialization)”。
参考文章
segmentfault.com/a/119000000… github.com/jackfrued/P…