加载存储在BytesIO对象中的json文件的正确方法是什么?

时间:2018-11-02 12:30:27

标签: python python-3.x

我要接收的数据是bytes,因此我需要临时的类似文件容器。据我所知,BytesIO类似文件的对象,但是json.load()不适用于该对象:

In [1]: import json
   ...: from io import BytesIO, TextIOWrapper

In [2]: d, b = dict(a=1, b=2), BytesIO()

In [3]: b.write(json.dumps(d).encode())
Out[3]: 16

In [4]: b.seek(0)
Out[4]: 0

In [5]: b.read()
Out[5]: b'{"a": 1, "b": 2}'

In [6]: b.seek(0)
Out[6]: 0

In [7]: json.load(b)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-233ac51d2711> in <module>()
----> 1 json.load(b)

/usr/lib/python3.5/json/__init__.py in load(fp, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    266         cls=cls, object_hook=object_hook,
    267         parse_float=parse_float, parse_int=parse_int,
--> 268         parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
    269 
    270 

/usr/lib/python3.5/json/__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    310     if not isinstance(s, str):
    311         raise TypeError('the JSON object must be str, not {!r}'.format(
--> 312                             s.__class__.__name__))
    313     if s.startswith(u'\ufeff'):
    314         raise JSONDecodeError("Unexpected UTF-8 BOM (decode using utf-8-sig)",

TypeError: the JSON object must be str, not 'bytes'

一种有效的方法:

In [8]: json.loads(b.getvalue().decode())
Out[8]: {'a': 1, 'b': 2}

另外一个,大概更有效吗?

In [10]: b.seek(0)
Out[10]: 0

In [11]: json.load(TextIOWrapper(b, encoding='utf-8'))
Out[11]: {'a': 1, 'b': 2}

我还有更多(更好)的选择吗?如果否,则应首选上述哪种方法?

4 个答案:

答案 0 :(得分:2)

出于两个原因,我建议使用TextIOWrapper

  1. 它为您提供了更多的控制权:不仅可以指定编码,还可以指定如何处理换行符(例如,如果您要解析csv数据,则应该进行换行)以及许多其他操作。
  2. 它允许您以流方式处理数据。假设您有一个无效的10MB文件json-fileobj.read().decode()会不必要地将所有10MB加载到内存中,但是如果您使用TextIOWrapper,那么在抛出JsonDecodeError之前仅会加载几个字节。

答案 1 :(得分:0)

由于您使用的是纯文本的JSON,因此应使用 "styles": [ "src/styles.scss", { "input": "node_modules/@angular/material/prebuilt-themes/purple-green.css" } ] 而不是io.StringIO

io.BytesIO

答案 2 :(得分:0)

如果您使用的是Python 3.5,请升级到3.6 +

3.5

>>> import sys                                                                                                   

>>> sys.version                                                                                                  
'3.5.0 (default, Feb 16 2017, 15:47:16) \n[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]'


>>> import json                                                                                                  

>>> from io import BytesIO                                                                                       

>>> d, b = dict(a=1, b=2), BytesIO()                                                                             

>>> b.write(json.dumps(d).encode())                                                                              
16


>>> b.seek(0)                                                                                                    
0


>>> json.load(b)                                                                                                 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/cmermingas/.pyenv/versions/3.5.0/lib/python3.5/json/__init__.py", line 268, in load
    parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, **kw)
  File "/Users/cmermingas/.pyenv/versions/3.5.0/lib/python3.5/json/__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'

the JSON object must be str, not 'bytes'

3.6

>>> import sys

>>> sys.version
'3.6.0 (default, Jul 10 2017, 22:19:26) \n[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)]'

>>> import json

>>> from io import BytesIO

>>> d, b = dict(a=1, b=2), BytesIO()

>>> b.write(json.dumps(d).encode())
16

>>> b.seek(0)
0

>>> json.load(b)
{'a': 1, 'b': 2}

答案 3 :(得分:-1)

使用 python 3.5 测试

import json
import socket, pycurl
from io import BytesIO

test_url='http://echo.jsontest.com/key/value/one/two' 

s = pycurl.Curl()
buffer= BytesIO()

s.setopt(s.URL, test_url)
s.setopt(s.HTTPHEADER, ['Host:' + 'localhost'])
s.setopt(s.WRITEDATA, buffer)
s.perform()

response = buffer.getvalue()
response = response.decode('utf-8')
# json.loads in python 3.5, not json.load
rj = json.loads(response)
srj = json.dumps(rj, indent=4, sort_keys=True)
print(srj)