使用 Python 即时处理 .json 文件 (read/write/change)
Working on .json files (read/write/change) on-the-fly with Python
最近我开始重写我以前写的游戏。我主要关心的是尝试解决它在单个文件上运行的主要问题(导致崩溃和数据溢出)。
在概念化更改时,我决定使用 .jsons 来即时存储数据(作为“自动保存”和 material 用于用户定期保存)。我尝试使用 json 库来创建可以让我轻松读取和写入数据的函数,方法如下:
read specific variable from .json -> operate on it, if needed ->
overwrite only that specific part of .json file
遗憾的是,无论我采用何种方式,我什至无法读取 .json 文件,更不用说编辑值了。到目前为止,我发现的所有“json.dump()”示例都试图将新行写入 .json 或替换文件,而不是简单地编辑特定值。我觉得在游戏的每一回合都重写整个文件根本没有效率。
到目前为止使用的代码(2 个变体,分别导致没有控制台输出或使用 _io.TextIOWrapper,我不知道如何将其转换为有用的数据):
def json_read(path, element):
import json
with open(path) as json_file:
data = json.load(json_file)
data = dict(data[element])
print (data)
def json_read(path, element):
import json
json_file = open(path, "r")
print (json.load(json_file))
我想要实现的主要目的是使函数对四个参数进行操作,简化形式如下所示:
def json_change(path, element, change_type, change_value):
if change_type == "replacement":
#replace .json variable [element] value with [change_value]
elif change_type == "maths":
#do mathematic equation (.json variable value [element] + [change_value]) and write its result back
elif change_type == "var_addition":
#write new variable called [element] in the end of .json file with value of [change_value]
另一个函数只是尝试从(路径、元素)参数中读取文件,它将 return 值供 json_change 或其他元素进一步使用。这个我已经尝试介绍了,如上所示。
我建议您只使用 json 库。读取文件一次并偶尔保存一次,假设每五分钟一次。
也许您想在单例模式中创建一个新的 class。这将确保您拥有一个保存当前最新信息的对象,并且只有该对象可以更新文件。
这里是关于这个 class 可能是什么样子的快速草图:
# SaveFileHandler.py
import json
class _SaveFileHandler:
def __init__(self):
self._data = {}
self._path = ""
def read(self, path):
self._path = path
with open(path) as file:
self._data = json.load(file)
def write(self):
with open(self._path) as file:
json.dump(self._data, file)
# now for every value you want data to have do the following
# it allows you to check the value for errors and makes the usage more readable
@property
def key(self):
return self._data["key"]
@key.setter
def key(self, value):
self._data["key"] = value
# the is the only object you will ever use
save_file = _SaveFileHandler()
您也可以直接在init中读取存档,这样可以确保您的数据始终可用。
当我自己找到解决方案时,正是我想要的方式,这是我最终使用的代码。
首先,我决定做两个具有相似系统但服务于不同目的的功能(数据的一般保存和加载系统;将只显示保存一个,因为它们仅在使用的目录上有所不同)。
参数如下所示:
- name = 玩家名称(保存在“saves/X”文件夹中)
- category = .json 使用的文件(有四个,每个用于保存的不同方面(stats/quests/world changes/inventory)
- dict_type = 决定返回值是包含来自保存的所有“变量”(真)还是仅选择的“变量”(假,默认)
- element = 特定的“变量”(如果 dict_type = True,可以是任何东西)
所以在这里我只是让函数读取特定文件并返回字典或“变量”本身。我还为 JSONDecoreError 制作了安全门,所以如果 .json (出于某种原因)为空,它将打印出来。
def save_read(name, category, element, dict_type=False):
import json
final_path = "saves/" + name + "/in_use/" + category + ".json"
data = {}
try:
with open (final_path) as json_file:
data = json.load(json_file)
if dict_type == False:
return data[element]
else:
return data
except json.decoder.JSONDecodeError:
print ("JSON File: " + final_path + " does not have any arguments. Skipping.")
下面的代码用于更详细地管理保存文件中的“变量”。它再次检查玩家名称、类别和元素(都与上面相同),但也有参数:
- change_type = 解释程序我们想用函数 运行ning 做什么(替换值,使其相对变化,或者如果需要新的甚至添加新的“变量”)
- change_value = 我们使用的值,通常是int、str或boolean
因此,根据“change_type”参数,“change_value”用于不同的目的(或者根本不使用,如果我们使用 save/load,在底部解释这个答案)。
def save_change(name, category, element, change_type, change_value, in_use=True):
#in_use=True is for all data elements within game, =False for saving game, since it uses different directory
import json
if in_use == True:
final_path = "saves/" + name + "/in_use/" + category + ".json"
#simply replacing value with new one (usually for string variables)
if change_type == "replace":
temp_dict = save_read(name, category, element, True)
temp_dict[element] = change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#math is intended to change value with +/- (use negative value to make it smaller)
elif change_type == "math":
temp_dict = save_read(name, category, element, True)
temp_dict[element] = temp_dict[element] + change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#math, but for (*) [rare case]
elif change_type == "math*":
temp_dict = save_read(name, category, element)
temp_dict[element] = temp_dict[element] * change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#math, but for (/) [rare case]
elif change_type == "math/":
temp_dict = save_read(name, category, element)
temp_dict[element] = temp_dict[element] / change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#var_add is intended to be dict; can be useful with version_updater especially
elif change_type == "var_add":
temp_dict = save_read(name, category, element, True)
temp_dict.update (change_value)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#var_add, but for deleting; change_value can be anything in this case
elif change_type == "var_del":
temp_dict = save_read(name, category, element, True)
temp_dict.remove (element)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#for loading the game (uses load_read)
elif change_type == "game_load":
temp_dict = load_read(name, category, element, True)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
elif in_use == False:
#for game saving | 'element' and 'change_value' can be anything
if change_type == "game_save":
final_path = "saves/" + name + "/" + category + ".json"
temp_dict = save_read(name, category, element, True)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
如果您想查看完整系统的精确代码(截至目前),也可以在 latest working commit on GitHub 上查看。它使用:
- system/json_manag.py - 用于一般管理(通信游戏<->“使用中保存”)
- system/save_system/save_load.py - 对于完整的 save/load 机制,运行
由玩家手动
它只是覆盖存档。jsons 或“游戏当前使用”。jsons,取决于它是加载还是保存。
最近我开始重写我以前写的游戏。我主要关心的是尝试解决它在单个文件上运行的主要问题(导致崩溃和数据溢出)。
在概念化更改时,我决定使用 .jsons 来即时存储数据(作为“自动保存”和 material 用于用户定期保存)。我尝试使用 json 库来创建可以让我轻松读取和写入数据的函数,方法如下:
read specific variable from .json -> operate on it, if needed -> overwrite only that specific part of .json file
遗憾的是,无论我采用何种方式,我什至无法读取 .json 文件,更不用说编辑值了。到目前为止,我发现的所有“json.dump()”示例都试图将新行写入 .json 或替换文件,而不是简单地编辑特定值。我觉得在游戏的每一回合都重写整个文件根本没有效率。
到目前为止使用的代码(2 个变体,分别导致没有控制台输出或使用 _io.TextIOWrapper,我不知道如何将其转换为有用的数据):
def json_read(path, element):
import json
with open(path) as json_file:
data = json.load(json_file)
data = dict(data[element])
print (data)
def json_read(path, element):
import json
json_file = open(path, "r")
print (json.load(json_file))
我想要实现的主要目的是使函数对四个参数进行操作,简化形式如下所示:
def json_change(path, element, change_type, change_value):
if change_type == "replacement":
#replace .json variable [element] value with [change_value]
elif change_type == "maths":
#do mathematic equation (.json variable value [element] + [change_value]) and write its result back
elif change_type == "var_addition":
#write new variable called [element] in the end of .json file with value of [change_value]
另一个函数只是尝试从(路径、元素)参数中读取文件,它将 return 值供 json_change 或其他元素进一步使用。这个我已经尝试介绍了,如上所示。
我建议您只使用 json 库。读取文件一次并偶尔保存一次,假设每五分钟一次。 也许您想在单例模式中创建一个新的 class。这将确保您拥有一个保存当前最新信息的对象,并且只有该对象可以更新文件。
这里是关于这个 class 可能是什么样子的快速草图:
# SaveFileHandler.py
import json
class _SaveFileHandler:
def __init__(self):
self._data = {}
self._path = ""
def read(self, path):
self._path = path
with open(path) as file:
self._data = json.load(file)
def write(self):
with open(self._path) as file:
json.dump(self._data, file)
# now for every value you want data to have do the following
# it allows you to check the value for errors and makes the usage more readable
@property
def key(self):
return self._data["key"]
@key.setter
def key(self, value):
self._data["key"] = value
# the is the only object you will ever use
save_file = _SaveFileHandler()
您也可以直接在init中读取存档,这样可以确保您的数据始终可用。
当我自己找到解决方案时,正是我想要的方式,这是我最终使用的代码。
首先,我决定做两个具有相似系统但服务于不同目的的功能(数据的一般保存和加载系统;将只显示保存一个,因为它们仅在使用的目录上有所不同)。 参数如下所示:
- name = 玩家名称(保存在“saves/X”文件夹中)
- category = .json 使用的文件(有四个,每个用于保存的不同方面(stats/quests/world changes/inventory)
- dict_type = 决定返回值是包含来自保存的所有“变量”(真)还是仅选择的“变量”(假,默认)
- element = 特定的“变量”(如果 dict_type = True,可以是任何东西)
所以在这里我只是让函数读取特定文件并返回字典或“变量”本身。我还为 JSONDecoreError 制作了安全门,所以如果 .json (出于某种原因)为空,它将打印出来。
def save_read(name, category, element, dict_type=False):
import json
final_path = "saves/" + name + "/in_use/" + category + ".json"
data = {}
try:
with open (final_path) as json_file:
data = json.load(json_file)
if dict_type == False:
return data[element]
else:
return data
except json.decoder.JSONDecodeError:
print ("JSON File: " + final_path + " does not have any arguments. Skipping.")
下面的代码用于更详细地管理保存文件中的“变量”。它再次检查玩家名称、类别和元素(都与上面相同),但也有参数:
- change_type = 解释程序我们想用函数 运行ning 做什么(替换值,使其相对变化,或者如果需要新的甚至添加新的“变量”)
- change_value = 我们使用的值,通常是int、str或boolean
因此,根据“change_type”参数,“change_value”用于不同的目的(或者根本不使用,如果我们使用 save/load,在底部解释这个答案)。
def save_change(name, category, element, change_type, change_value, in_use=True):
#in_use=True is for all data elements within game, =False for saving game, since it uses different directory
import json
if in_use == True:
final_path = "saves/" + name + "/in_use/" + category + ".json"
#simply replacing value with new one (usually for string variables)
if change_type == "replace":
temp_dict = save_read(name, category, element, True)
temp_dict[element] = change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#math is intended to change value with +/- (use negative value to make it smaller)
elif change_type == "math":
temp_dict = save_read(name, category, element, True)
temp_dict[element] = temp_dict[element] + change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#math, but for (*) [rare case]
elif change_type == "math*":
temp_dict = save_read(name, category, element)
temp_dict[element] = temp_dict[element] * change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#math, but for (/) [rare case]
elif change_type == "math/":
temp_dict = save_read(name, category, element)
temp_dict[element] = temp_dict[element] / change_value
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#var_add is intended to be dict; can be useful with version_updater especially
elif change_type == "var_add":
temp_dict = save_read(name, category, element, True)
temp_dict.update (change_value)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#var_add, but for deleting; change_value can be anything in this case
elif change_type == "var_del":
temp_dict = save_read(name, category, element, True)
temp_dict.remove (element)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
#for loading the game (uses load_read)
elif change_type == "game_load":
temp_dict = load_read(name, category, element, True)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
elif in_use == False:
#for game saving | 'element' and 'change_value' can be anything
if change_type == "game_save":
final_path = "saves/" + name + "/" + category + ".json"
temp_dict = save_read(name, category, element, True)
with open (final_path,'w') as file:
json.dump(temp_dict, file, indent = 2)
如果您想查看完整系统的精确代码(截至目前),也可以在 latest working commit on GitHub 上查看。它使用:
- system/json_manag.py - 用于一般管理(通信游戏<->“使用中保存”)
- system/save_system/save_load.py - 对于完整的 save/load 机制,运行 由玩家手动
它只是覆盖存档。jsons 或“游戏当前使用”。jsons,取决于它是加载还是保存。