记录信息
比如说我写了这样一段程序,记录了爱吃的食物:
food_list = []
while True:
c = input("输入1添加新的食物,输入2查询已添加的食物,输入exit退出:")
if c == "1":
new_food = input("输入你喜欢的食物:")
food_list.append(new_food)
print("添加成功!")
elif c == "2":
for i in food_list:
print(i, end=" ")
print()
elif c == "exit":
print("谢谢,下次再见!")
break
但是,很快就会发现这样一个问题,当我们下次再运行程序的时候,上次输入的内容全都没了,怎么会这样呢?
原理其实很简单,在程序运行的时候,我们存储的信息放入了python的列表之中,这些信息是保存在内存之中的,当程序运行结束,这些信息就没了。
那么,如果我希望将输入保存起来,下次还能看到,该怎么办呢?这个时候,就需要将要保存的内容存储到文件了。
json存储数据
json介绍
json,全名:JavaScript Object Notation,是一种轻量级的数据交换格式,最初基于JavaScript,但是后来随着发展,现在几乎被所有编程语言支持。
json数据非常适合人类阅读和编写,也可以在网络应用中进行数据传输,当然也可以作为数据存储。最常见的json数据类型包括object(对象),以及array(数组)。
json对象:
{
"name": "仙草",
"age": 18,
"isStudent": false
}
json数组:
["啃达鸡美食", "疯狂星期四", "可口可乐"]
对于python中的数据类型来说,列表会被保存为json数组,而字典会被保存为json对象。
json写入文件
import json
# 需要保存的数据
data = [1, 2, 3, 4, 5]
# 转为json数据
json_data = json.dumps(data)
# 写入文件
with open("record.json", "w") as f:
f.write(json_data)
json文件读取
import json
with open("record.json", "r") as f:
json_data = f.read()
data = json.loads(json_data)
为程序添加保存读取
import json
try:
with open("food_list.json", "r") as file:
food_list = json.load(file)
except FileNotFoundError:
food_list = []
while True:
c = input("输入1添加新的食物,输入2查询已添加的食物,输入exit退出:")
if c == "1":
new_food = input("输入你喜欢的食物:")
food_list.append(new_food)
print("添加成功!")
with open("food_list.json", "w") as file:
file.write(json.dumps(food_list))
elif c == "2":
for i in food_list:
print(i, end=" ")
print()
elif c == "exit":
print("谢谢,下次再见!")
break
pickle序列化
pickle介绍
pickle可以对一个python对象进行二进制序列化以及反序列化,比起json,使用pickle的一个好处是,pickle可以保存任意一个python对象,例如类或者函数,但是json则不能直接这样做。
注意:pickle具有危险性,因此,不要加载你不信任的内容,必须使用可信任的数据。
pickle写入文件
import pickle
data = [1, 2, 3, 4, 5]
with open("data.pkl", "wb") as f:
pickle.dump(data, f)
pickle文件读取
import pickle
with open("data.pkl", "rb") as f:
loaded_data = pickle.load(f)
print(loaded_data)
pickle具有安全风险
在python的官方文档上,有这样一段重要提示:“如果解序化的数据是由手段高明的攻击者精心设计的,这种不受信任来源的pickle数据可以执行任意代码。”
很多人对此有一些困惑,真的有这么严重吗?答案是肯定的。假设,有这样一段恶意代码:
import pickle
import os
class Example:
def __reduce__(self):
return (os.system, ('echo "不能随便使用危险的代码!"',))
malicious_data = pickle.dumps(Example())
with open("malicious.pkl", "wb") as file:
file.write(malicious_data)
此时, 当代码重新被加载的时候,就会执行恶意代码,调用系统命令。
import pickle
with open("malicious.pkl", "rb") as file:
data = pickle.load(file)
安全使用pickle
一种安全使用自己生成的pickle的方法,是使用hmac对序列化的数据进行签名,下次使用的时候进行签名的认证,以保证当初生成的pickle没有被他人篡改。下面是一种可能的实现:
import pickle
import hmac
import hashlib
secret_key = b"your-secret-key"
def save_signed_pickle(data, file_path, key):
# 使用pickle序列化数据
serialized_data = pickle.dumps(data)
# 生成签名
signature = hmac.new(key, serialized_data, hashlib.sha256).digest()
# 将签名和序列化数据一起保存到文件
with open(file_path, "wb") as f:
f.write(signature)
f.write(serialized_data)
def load_signed_pickle(file_path, key):
# 从文件加载数据并验证签名
with open(file_path, "rb") as f:
signature = f.read(32) # 签名长度为32字节,因此恰好可以读取到签名
serialized_data = f.read()
# 重新计算签名并进行验证
expected_signature = hmac.new(key, serialized_data, hashlib.sha256).digest()
if hmac.compare_digest(signature, expected_signature):
# 签名匹配,说明数据未被篡改,可以安全反序列化
return pickle.loads(serialized_data)
else:
# 签名不匹配,数据可能已被篡改
raise ValueError("Data integrity check failed!")