文件和异常
实际开发中常常会遇到对数据进行持久化操作的场景,而实现数据持久化最直接简单的方式就是将数据保存到文件中。
在 Python 中实现文件的读写操作其实非常简单,通过 Python 内置的 open 函数,我们可以指定文件名、操作模式、编码信息等来获得操作文件的对象,接下来就可以对文件进行读写操作了。这里所说的操作模式是指要打开什么样的文件(字符文件还是二进制文件)以及做什么样的操作(读、写还是追加)。
操作模式 | 具体含义 |
r | 读写 |
w | 写入(会截断之前的内容) |
x | 写入,如果文件已经存在会产生异常 |
a | 追加,将内容写入到已有文件的末尾 |
b | 二进制模式 |
t | 文本模式 |
+ | 更新(可读又可写) |
读写文本文件
读取文本文件时,需要在使用 open 函数时指定好带路径的文件名(可以使用相对路径或绝对路径)并将文件模式设置为 r (如果不指定,默认值也是'r'
),然后通过 encoding 参数指定编码(如果不指定,默认值是 None,那么在读取文件时使用的是操作系统默认的编码),如果不能保证保存文件时使用的编码方式与 encoding 参数指定的编码方式是一致的,那么就可能因无法解码字符而导致读取失败。
def main():
file = open('test.txt', 'r', encoding='utf-8')
print(file.read())
file.close()
if __name__ == '__main__':
main()
如果 open 函数指定的文件并不存在或者无法打开,那么将引发异常状况导致程序崩溃。为了让代码有一定的健壮性和容错性,我们可以使用 Python 的异常机制对可能在运行时发生状况的代码进行适当的处理。
def main():
file = None
try:
file = open('test.txt', 'r', encoding='utf-8')
print(file.read())
except FileNotFoundError:
print('无法打开指定的文件!')
except LookupError:
print('指定了未知的编码!')
except UnicodeDecodeError:
print('读取文件时解码错误!')
finally:
if file:
file.close()
if __name__ == '__main__':
main()
在 Python 中,我们可以将那些在运行时可能会出现状况的代码放在 try 代码块中,在 try 代码块的后面可以跟上一个或多个 except 来捕获可能出现的异常状况。例如在上面读取文件的过程中,文件找不到会引发 FileNotFoundError ,指定了未知的编码会引发 LookupError ,而如果读取文件时无法按指定方式解码会引发 UnicodeDecodeError ,我们在 try 后面跟上了三个 except 分别处理这三种不同的异常状况。最后我们使用 finally 代码块来关闭打开的文件,释放掉程序中获取的外部资源,由于 finally 块的代码不论程序正常还是异常都会执行到(甚至是调用了 sys 模块的 exit 函数退出 Python 环境, finally 块都会被执行,因为 exit 函数实质上是引发了 SystemExit 异常),因此我们通常把 finally 块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。如果不愿意在 finally 代码块中关闭文件对象释放资源,也可以使用上下文语法,通过 with 关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源。
def main():
try:
with open('test.txt', 'r', encoding='utf-8') as file:
print(file.read())
except FileNotFoundError:
print('无法打开指定的文件!')
except LookupError:
print('指定了未知的编码!')
except UnicodeDecodeError:
print('读取文件时解码错误!')
if __name__ == '__main__':
main()
除了使用文件对象的 read 方法读取文件之外,还可以使用 for-in 循环逐行读取或者用 readlines 方法将文件按行读取到一个列表容器中。
def main():
# 一次性读取整个文件内容
with open('test.txt', 'r', encoding='utf-8') as file:
print(file.read())
# 通过for-in循环逐行读取
with open('test.txt', mode='r') as file:
for line in file:
print(line, end='')
print()
# 读取文件按行读取到列表中
with open('test.txt') as file:
lines = file.readlines()
print(lines)
if __name__ == '__main__':
main()
要将文本信息写入文件文件也非常简单,在使用 open 函数时指定好文件名并将文件模式设置为 w 即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为 a 。如果要写入的文件不存在会自动创建文件而不是引发异常。
将1~99分别写入两个文件中(1~50写入test1.txt,51~99写入test2.txt)。
def main():
filenames = ('test1.txt', 'test2.txt')
file_list = []
try:
for filename in filenames:
file_list.append(open(filename, 'a', encoding='utf-8'))
for number in range(1, 100):
if number < 100:
file_list[0].write(str(number) + '\n')
else:
file_list[1].write(str(number) + '\n')
except IOError as ex:
print(ex)
print('写文件时发生错误!')
finally:
for file in file_list:
file.close()
print('操作完成!')
if __name__ == '__main__':
main()
读写二进制文件
在了解完文本文件的读写后,再学习二进制文件的读写就很简单,只需要在模式中加入 b 即可。
实现复制图片的功能。
def main():
try:
with open('tp1.jpg', 'rb') as file1:
data = file1.read()
print(type(data)) # <class 'bytes'>
with open('tp2.jpg', 'wb') as file2:
file2.write(data)
except FileNotFoundError as e:
print('指定的文件无法打开.')
except IOError as e:
print('读写文件异常.')
if __name__ == '__main__':
main()
读写JSON文件
我们已经了解如何将文本数据和二进制数据保存到文件中,那么又该如何将一个列表或者一个字典中的数据保存到文件中呢?
列表和字典中的数据可以通过 JSON 格式保存到文件中。
JSON 是 “JavaScript Object Notation” 的缩写,它本来是 JavaScript 语言中创建对象的一种字面量语法,现在已经被广泛的应用于跨平台跨语言的数据交换,原因很简单,因为JSON也是纯文本,任何系统任何编程语言处理纯文本都是没有问题的。目前 JSON 基本上已经取代了 XML 作为异构系统间交换数据的事实标准。
简单的 JSON 例子。
{
"name": "小明",
"age": 12,
"phone": 1888888,
"friends": ["小红", "小白"],
"toys": [
{"tname": "悠悠球", "price": 25},
{"tname": "陀螺", "price": 10},
{"tname": "遥控汽车", "price": 200}
]
}
上面的 JSON 跟 Python 中的字典其实是一样一样的,事实上 JSON 的数据类型和 Python 的数据类型是很容易找到对应关系的。
JSON | Python |
object | dict |
array | list |
string | str |
number | int/float |
true/false | True/False |
null | None |
使用 Python 中的 json 模块就可以将字典或列表以 JSON 格式保存到文件中。
import json
def main():
mydict =
{
"name": "小明",
"age": 12,
"phone": 1888888,
"friends": ["小红", "小白"],
"toys": [
{"tname": "悠悠球", "price": 25},
{"tname": "陀螺", "price": 10},
{"tname": "遥控汽车", "price": 200}
]
}
try:
with open('data.json', 'w', encoding='utf-8') as file:
json.dump(mydict, file)
except IOError as e:
print(e)
print('保存数据完成!')
if __name__ == '__main__':
main()
json模块主要有四个比较重要的函数,分别是:
dump
- 将Python对象按照JSON格式序列化到文件中dumps
- 将Python对象处理成JSON格式的字符串load
- 将文件中的JSON数据反序列化成对象loads
- 将字符串的内容反序列化成Python对象
序列化(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换为可以存储或传输的形式,这样在需要的时候能够恢复到原先的状态,而且通过序列化的数据重新获取字节时,可以利用这些字节来产生原始对象的副本(拷贝)。与这个过程相反的动作,即从一系列字节中提取数据结构的操作,就是反序列化(deserialization)。