Python解析manifest.json触发JSONDecodeError错误求助
UTF-8 BOM导致JSON解析失败的解决办法
问题场景
开发Mod管理器时,读取mod的manifest.json文件获取名称、版本等信息时触发JSONDecodeError,输出显示文件开头存在字符,即使手动重写文件问题依然存在。
相关文件内容
manifest.json
{ "name": "HookGenPatcher", "version_number": "0.0.5", "website_url": "https://github.com/harbingerofme/Bepinex.Monomod.HookGenPatcher", "description": "Generates MonoMod.RuntimeDetour.HookGen's MMHOOK file during the BepInEx preloader phase.", "dependencies": [] }
原始代码
from json import JSONDecoder import os from zipfile import is_zipfile, ZipFile json = JSONDecoder() PLUGIN_PATH: str = "./mods" plugins: dict[str: dict[str: str]] = {} for mod in os.listdir(path=PLUGIN_PATH): mod_path: str = f"{PLUGIN_PATH}/{mod}" if is_zipfile(filename=mod_path): folder_path: str = ".".join(mod_path.split(sep=".")[:-1]) os.mkdir(path=folder_path) mod_zip = ZipFile(file=mod_path) mod_zip.extractall(path=folder_path) mod_zip.close() os.remove(path=mod_path) with open(file=f"{mod_path}/manifest.json", mode="r") as f: x: str = f.read() y: list = [] for line in x.splitlines(): y.append(line.strip()) y = "".join(y) print(y) mod_json: dict = json.decode(s=y) plugins[mod] = mod_json print(plugins)
报错信息
{"name": "HookGenPatcher","version_number": "0.0.5","website_url": "https://github.com/harbingerofme/Bepinex.Monomod.HookGenPatcher","description": "Generates MonoMod.RuntimeDetour.HookGen's MMHOOK file during the BepInEx preloader phase.","dependencies": []} Traceback (most recent call last): File "d:\OneDrive\Code\BetterLCMods\main.pyw", line 58, in <module> mod_json: dict = json.decode(s = y) ^^^^^^^^^^^^^^^^^^ File "E:\Python\Lib\json\decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Python\Lib\json\decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
原因分析
文件开头的是UTF-8字节顺序标记(BOM),部分编辑器(如Windows记事本)保存UTF-8文件时会自动添加该标记。Python默认以utf-8编码读取文件时不会去除BOM,导致JSON解析器无法识别开头的无效字符,触发错误。此外,原始代码解压zip后未更新mod_path为文件夹路径,可能导致后续文件读取异常。
解决方案
方法1:读取文件时指定utf-8-sig编码
Python的utf-8-sig编码会自动识别并去除UTF-8 BOM,是最简便的解决方式:
with open(file=f"{mod_path}/manifest.json", mode="r", encoding="utf-8-sig") as f: mod_json: dict = json.load(f)
方法2:手动去除字符串开头的BOM
如果无法指定编码,可手动检查并移除BOM标记:
with open(file=f"{mod_path}/manifest.json", mode="r") as f: x: str = f.read() if x.startswith('\ufeff'): x = x[1:] mod_json: dict = json.decode(x)
补充修复:解压后更新mod_path
解压zip后,需将mod_path更新为解压后的文件夹路径,否则会找不到manifest.json:
if is_zipfile(filename=mod_path): folder_path: str = ".".join(mod_path.split(sep=".")[:-1]) os.mkdir(path=folder_path) mod_zip = ZipFile(file=mod_path) mod_zip.extractall(path=folder_path) mod_zip.close() os.remove(path=mod_path) mod_path = folder_path
优化后的完整代码
from json import load as json_load import os from zipfile import is_zipfile, ZipFile PLUGIN_PATH: str = "./mods" plugins: dict[str, dict[str, str | list]] = {} for mod in os.listdir(PLUGIN_PATH): mod_path: str = os.path.join(PLUGIN_PATH, mod) if is_zipfile(mod_path): folder_path: str = os.path.splitext(mod_path)[0] os.makedirs(folder_path, exist_ok=True) with ZipFile(mod_path) as mod_zip: mod_zip.extractall(folder_path) os.remove(mod_path) mod_path = folder_path manifest_path = os.path.join(mod_path, "manifest.json") if os.path.exists(manifest_path): with open(manifest_path, "r", encoding="utf-8-sig") as f: mod_json = json_load(f) plugins[mod] = mod_json print(plugins)
内容的提问来源于stack exchange,提问作者PhaseAmaze
相关产品推荐
相关产品推荐

