记录信息
比如说我写了这样一段程序,记录了爱吃的食物:
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 jsonwith open("record.json", "r") as f:json_data = f.read()data = json.loads(json_data)
为程序添加保存读取
import jsontry: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 pickledata = [1, 2, 3, 4, 5]with open("data.pkl", "wb") as f:pickle.dump(data, f)
pickle文件读取
import picklewith open("data.pkl", "rb") as f:loaded_data = pickle.load(f)print(loaded_data)
pickle具有安全风险
在python的官方文档上,有这样一段重要提示:“如果解序化的数据是由手段高明的攻击者精心设计的,这种不受信任来源的pickle数据可以执行任意代码。”
很多人对此有一些困惑,真的有这么严重吗?答案是肯定的。假设,有这样一段恶意代码:
import pickle
import osclass 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 picklewith open("malicious.pkl", "rb") as file:data = pickle.load(file)
安全使用pickle
一种安全使用自己生成的pickle的方法,是使用hmac对序列化的数据进行签名,下次使用的时候进行签名的认证,以保证当初生成的pickle没有被他人篡改。下面是一种可能的实现:
import pickle
import hmac
import hashlibsecret_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!")