python如何通过json以及pickle读写保存数据

记录信息

比如说我写了这样一段程序,记录了爱吃的食物:

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!")

上一篇:Python操作MySQL


下一篇:初识算法 · 前缀和(1)