【2】文件读写-2-7-python读写json(JSON)

Python的Json模块序列化与反序列化的过程分别是 encoding和 decoding

  • encoding:把一个Python对象编码转换成Json字符串
  • decoding:把Json格式字符串解码转换成Python对象

一、简介

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。

JSON建构于两种结构:

“名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。

值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。 这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。

jso官方说明参见:http://json.org/

Python操作json的标准api库参考:http://docs.python.org/library/json.html

二、举个栗子哈

import json
data = [{'a':"A",'b':(2,4),'c':3.0}]  #list对象
print "DATA:",repr(data)
data_string = json.dumps(data)
print "JSON:",data_string
输出:
DATA: [{'a':'A','c':3.0,'b':(2,4)}] #python的dict类型的数据是没有顺序存储的
JSON: [{"a":"A","c":3.0,"b":[2,4]}]  
JSON的输出结果与DATA很相似,除了一些微妙的变化,如python的元组类型变成了Json的数组,

编码后的json格式字符串紧凑的输出,而且也没有顺序,因此dumps方法提供了一些可选的参数,让输出的格式提高可读性,如sort_keys是告诉编码器按照字典排序(a到z)输出。

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
print 'DATA:', repr(data)
unsorted = json.dumps(data)
print 'JSON:', json.dumps(data)
print 'SORT:', json.dumps(data, sort_keys=True)
输出:
DATA: [{'a': 'A', 'c': 3.0, 'b': (2, 4)}]
JSON: [{"a": "A", "c": 3.0, "b": [2, 4]}]
SORT: [{"a": "A", "b": [2, 4], "c": 3.0}

indent参数根据数据格式缩进显示,读起来更加清晰:

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
print 'DATA:', repr(data)
print 'NORMAL:', json.dumps(data, sort_keys=True)
print 'INDENT:', json.dumps(data, sort_keys=True, indent=2)
输出:
DATA: [{'a': 'A', 'c': 3.0, 'b': (2, 4)}]
NORMAL: [{"a": "A", "b": [2, 4], "c": 3.0}]
INDENT: [
  {
	"a": "A",
	"b": [
	  2,
	  4
	],
	"c": 3.0
  }
]

separators参数的作用是去掉**,,:后面的空格**,从上面的输出结果都能看到", :“后面都有个空格,这都是为了美化输出结果的作用,但是在我们传输数据的过程中,越精简越好,冗余的东西全部去掉,因此就可以加上separators参数:

>>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
'[1,2,3,{"4":5,"6":7}]'

import json
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
print 'DATA:', repr(data)
print 'repr(data)             :', len(repr(data))
print 'dumps(data)            :', len(json.dumps(data))
print 'dumps(data, indent=2)  :', len(json.dumps(data, indent=2))
print 'dumps(data, separators):', len(json.dumps(data, separators=(',',':')))
输出:
DATA: [{'a': 'A', 'c': 3.0, 'b': (2, 4)}]
repr(data)             : 35
dumps(data)            : 35
dumps(data, indent=2)  : 76
dumps(data, separators): 29

skipkeys参数,在encoding过程中,dict对象的key只可以是string对象,如果是其他类型,那么在编码过程中就会抛出ValueError的异常。skipkeys可以跳过那些非string对象当作key的处理.

import json
data= [ { 'a':'A', 'b':(2, 4), 'c':3.0, ('d',):'D tuple' } ]
try:
	print json.dumps(data)
except (TypeError, ValueError) as err:
	print 'ERROR:', err
print 
print json.dumps(data, skipkeys=True)
输出:
ERROR: keys must be a string
[{"a": "A", "c": 3.0, "b": [2, 4]}]

二、读写数据

json读文件

	with open("temp.json","w") as f:
		json.dump(data,f,indent= 4,sort_keys=True)

	with open("temp.json","r") as m:
		data_string = json.load(m)
print data_string

json格式字符串写入到文件流中

上面的例子都是在内存中操作的,如果对于大数据,把他编码到一个类文件(file-like)中更合适,load()和dump()方法就可以实现这样的功能。

import json
import tempfile
data = [ { 'a':'A', 'b':(2, 4), 'c':3.0 } ]
f = tempfile.NamedTemporaryFile(mode='w+')
json.dump(data, f)
f.flush()
print open(f.name, 'r').read()
输出:
[{"a": "A", "c": 3.0, "b": [2, 4]}]

类似的:

import json
import tempfile

f = tempfile.NamedTemporaryFile(mode='w+')
f.write('[{"a": "A", "c": 3.0, "b": [2, 4]}]')
f.flush()
f.seek(0)
print json.load(f)
输出:
[{u'a': u'A', u'c': 3.0, u'b': [2, 4]}]

四、讨论

4.1 dumps与Loads的区别

  • json.dumps : dict转成str
  • json.loads:str转成dict

4.2 中文字符的处理

for one_result in os.listdir(temp_dir):
    if one_result.startswith('.'):
        continue

    one_result2 = os.path.join(temp_dir,one_result)

    print one_result2
    with open(one_result2,'r') as data1:
        data_string1 = json.load(data1)
        # print data_string1
        result_list += data_string1

with open(result, 'w') as data3:
    json_info = json.dumps(result_list, ensure_ascii = False).encode('utf-8')
    print json_info
    data3.write(unicode(json_info))

读写包含中文字符的json文件

四、报错

4.1. unicode' object has no attribute ‘read’ json

解决办法: load 改成Loads

json.loads(jsondata)

案例:

test_id = "http://openapi.youdao.com/api?q={query_info}&from=EN&to=zh_CHS&appKey={appKey}&salt={salt}&sign={sign_info2}" .format(**locals())
r = requests.get(test_id)
result_info = r.text
result = json.loads(result_info)
trans_result = result["translation"][0]	

4.2 大量数据,里面有多行多列,出现类似标题报错

raise JSONDecodeError(“Extra data”, s, end)
json.decoder.JSONDecodeError: Extra data: line 2 column 1 (char 104)

可以逐行读取,然后再处理成列表:

import json
# 由于文件中有多行,直接读取会出现错误,因此一行一行读取

file = open("papers.json", 'r', encoding='utf-8')
papers = []
for line in file.readlines():
    dic = json.loads(line)
    papers.append(dic)
print(len(papers))

参考资料

药企,独角兽,苏州。团队长期招人,感兴趣的都可以发邮件聊聊:tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn