我正在尝试解码大型 utf-8 json 文件 (2.2 GB)。我像这样加载文件:
f = codecs.open('output.json', encoding='utf-8')
data = f.read()
如果我尝试执行以下任一操作:json.load
、json.loads
或 json.JSONDecoder().raw_decode
我会得到错误:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-40-fc2255017b19> in <module>()
----> 1 j = jd.decode(data)
/usr/lib/python2.7/json/decoder.pyc in decode(self, s, _w)
367 end = _w(s, end).end()
368 if end != len(s):
--> 369 raise ValueError(errmsg("Extra data", s, end, len(s)))
370 return obj
371
ValueError: Extra data: line 1 column -2065998994 - line 1 column 2228968302
(char -2065998994 - 2228968302)
uname -m
显示 x86_64
和
> python -c 'import sys;print("%x" % sys.maxsize, sys.maxsize > 2**32)'
('7fffffffffffffff', True)`
所以我应该是 64 位的,整数大小应该不是问题。
但是,如果我运行:
jd = json.JSONDecoder()
len(data) # 2228968302
j = jd.raw_decode(data)
j[1] # 2228968302
raw_decode
返回的元组中的第二个值是字符串的末尾,因此 raw_decode
似乎解析了整个文件,末尾似乎没有垃圾。
那么,我应该对 json 做些什么不同的事情吗? raw_decode
实际上解码了整个文件吗?为什么 json.load(s)
失败了?
最佳答案
我想将其添加为评论,但评论中的格式化功能太有限了。
盯着源码,
raise ValueError(errmsg("Extra data", s, end, len(s)))
调用这个函数:
def errmsg(msg, doc, pos, end=None):
...
fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})'
return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end)
格式的 (char {5} - {6})
部分是您显示的错误消息的这一部分:
(char -2065998994 - 2228968302)
所以,在errmsg()
中,pos
是-2065998994,end
是2228968302。看哪! ;-):
>>> pos = -2065998994
>>> end = 2228968302
>>> 2**32 + pos
2228968302L
>>> 2**32 + pos == end
True
也就是说,pos
和end
“真的”是一样的。从调用 errmsg()
的地方返回,这意味着 end
和 len(s)
实际上也是一样的 - 但是 end
被视为 32 位有符号整数。 end
又来自正则表达式匹配对象的 end()
方法。
所以这里真正的问题似乎是正则表达式引擎中的 32 位限制/假设。我鼓励你open a bug report !
稍后:回答你的问题,是的,raw_decode()
正在解码整个文件。其他方法调用 raw_decode()
,但随后添加(失败!)健全性检查。
关于python - 2.2GB JSON 文件解析不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19215847/