2013-10-07 40 views
6

我想解碼一個大型的utf-8 json文件(2.2 GB)。我加載文件,如下所示:2.2GB JSON文件解析不一致

f = codecs.open('output.json', encoding='utf-8') 
data = f.read() 

如果我嘗試做任何的:json.loadjson.loadsjson.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)失敗?

+2

你在運行什麼樣的系統? 2。對於一個有符號的32位整數,20億是太大了,而異常細節中的負數表明你遇到了問題。 –

+0

不考慮底層代碼,我會猜測函數將輸入轉換爲字符串,並且他們嘗試處理該大小的字符串時出現溢出問題。 「原始」版本可能不會,因此能夠解析整個事情。 – Gabe

+0

@TimPeters我將此添加到我的問題中,但我在64位體系結構上。 –

回答

9

我會將此添加爲評論,但評論中的格式功能太有限。

源代碼凝望,

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 

也就是說,posend是 「真的」 一樣。從errmsg()被調用的位置返回,這意味着endlen(s)也是如此 - 但end被視爲32位有符號整數。 end又來自正則表達式匹配對象的方法end()

所以這裏真正的問題似乎是在正則表達式引擎中的32位限制/假設。我鼓勵你們open a bug report

稍後:要回答您的問題,yes,raw_decode()正在解碼整個文件。其他方法請致電raw_decode(),但之後添加(失敗!)完整性檢查。