Python3中的json模块使用详解


Posted in Python onMay 05, 2018

1. 概述

JSON (JavaScript Object Notation)是一种使用广泛的轻量数据格式. Python标准库中的json模块提供了JSON数据的处理功能.

Python中一种非常常用的基本数据结构就是字典(Dictionary). 它的典型结构如下:

d = {
'a': 123,
'b': {
'x': ['A', 'B', 'C']
}
}

而JSON的结构如下:

{
"a": 123,
"b": {
"x": ["A", "B", "C"]
}
}

可以看到, Dictionary和JSON非常接近, 而Python中的json库提供的主要功能, 也是两者之间的转换.

2. 读取JSON

json.loads方法可以将包含了一个JSON数据的str, bytes或者bytearray对象, 转化为一个Python Dictionary. 它的完型接口签名如下:

json.loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

2.1 最简单的例子

json.loads最基本的使用方式就是将一个包含JSON数据的str传递给这个方法:

>>> json.loads('{"a": 123}')
{'a': 123}

注意

在Python中, str值可以放在一对单引号中, 也可以放在一对双引号中:

>>> 'ABC' == "ABC"
True

所以, 在定义Dictionary的str类型的键和值的时候, 使用单引号或者双引号都是合法和等价的:

>>> {"a": 'ABC'} == {'a': "ABC"}
True

但是, 在JSON中, 字符串数据只能放在双引号中, 因而json.loads方法处理的字符串的JSON内容中, 字符串必须使用双引号. 否则就会发生解码错误:

>>> json.loads("{'a': 123}")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/decoder.py", line 355, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

如果被处理的Python字符串是包含在双引号中的, 那么JSON中的双引号就需要转义:

>>> json.loads("{\"a\": 123}")
{'a': 123}

2.2 bytes和bytearray数据

对于内容是JSON数据的bytes和bytearray, json.loads方法也可以处理:

>>> json.loads('{"a": 123}'.encode('UTF-8'))
{'a': 123}
>>> json.loads(bytearray('{"a": 123}', 'UTF-8'))
{'a': 123}

2.3 编码格式

json.loads的第二个参数是encoding没有实际作用.

由于Python 3中str类型总是使用UTF-8编码, 所以s参数为str类型时, json.loads方法自动使用UTF-8编码. 并且, str不能以BOM字节开头.

当s参数为bytes或者bytearray时, json.loads方法会自动判断为UTF-8, UTF-16还是UTF-32编码. 默认也是将其按照UTF-8编码转化为str对象进行后续处理.

2.4 数据类型转换

JSON可以表示四种主类型数据

  • 1.字符串 string
  • 2.数字 number
  • 3.布尔类 boolean
  • 4.空值 null

以及两结数据结构

  • 1.对象 object
  • 2.数组 array

默认实现中, JSON和Python之间的数据转换对应关系如下表:

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

实际转换情况如下例:

>>> json.loads("""
... {
... "obj": {
... "str": "ABC",
... "int": 123,
... "float": -321.89,
... "bool_true": true,
... "bool_false": false,
... "null": null,
... "array": [1, 2, 3]
... }
... }""")
{'obj': {'str': 'ABC', 'int': 123, 'float': -321.89, 'bool_true': True, 'bool_false': False, 'null': None, 'array': [1, 2, 3]}}

对于JSON中数字number类型的数据, 有以下几点需要注意:

1.JSON中的实数real number类型的精度不能超过Python中的float类型的精度范围, 否则就有精度损失. 如下例:

>>> json.loads('3.141592653589793238462643383279')
3.141592653589793

2.JSON标准不包括非数字NaN, 正无穷Infinity和负无穷-Infinity, 但是json.loads方法默认会将JSON字符串中的NaN, Infinity, -Infinity转化为Python中的float('nan'), float('inf')和float('-inf'). 注意, 这里JSON中的NaN, Infinity, -Infinity必须大小写正确并且拼写完整. 如下例

>>> json.loads('{"inf": Infinity, "nan": NaN, "ninf": -Infinity}')
{'inf': inf, 'nan': nan, 'ninf': -inf}

2.5 自定义JSON对象转换类型

json.loads默认将JSON中的对象数据转化为Dictionary类型, object_hook参数可以用来改变构造出的对象.

object_hook接受一个函数, 这个函数的输入参数为JSON中对象数据转化出的Dictionary对象, 其返回值则为自定义的对象. 如下例所示:

>>> class MyJSONObj:
... def __init__(self, x):
... self.x = x
...
>>> def my_json_obj_hook(data):
... print('obj_hook data: %s' % data)
... return MyJSONObj(data['x'])
...
>>> result = json.loads('{"x": 123}', object_hook=my_json_obj_hook)
obj_hook data: {'x': 123}
>>> type(result)
<class '__main__.MyJSONObj'>
>>> result.x
123

当JSON中的对象有嵌套时, json.loads方法会按照深度优先的方式遍历对象树, 将各层的对象数据传递给object_hook. 叶节点的JSON对象构造出的Python对象, 会作为父节点的一个值, 传递给父节点的object_hook方法. 如下例:

>>> class MyJSONObj:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> def my_json_obj_hook(data):
... print('obj_hook data: %s' % data)
... return MyJSONObj(**data)
...
>>> result = json.loads('{"x": {"x": 11, "y": 12}, "y": {"x": 21, "y":22}}', object_hook=my_json_obj_hook)
obj_hook data: {'x': 11, 'y': 12}
obj_hook data: {'x': 21, 'y': 22}
obj_hook data: {'x': <__main__.MyJSONObj object at 0x10417ef28>, 'y': <__main__.MyJSONObj object at 0x10417ed68>}

除了object_hook参数以外, 还有一个object_pairs_hook参数. 这个参数同样可以用来改变json.loads方法构造出的Python对象的类型. 这个参数和object_hook的不同, 在于传入的方法所接收到的输入数据不是一个Dictionary, 而是一个包含tuple的list. 每个tuple都有两个元素, 第一个元素是JSON数据中的键, 第二个元素是这个键对应的值. 如JSON对象

{
"a": 123,
"b": "ABC"
}

对应的输入数据是

[
('a': 123),
('b', 'ABC')
]

当调用json.loads方法时, 同时指定object_hook和object_pairs_hook, object_pairs_hook会覆盖object_hook参数.

2.6 自定义JSON数字转换类型

默认实现中, JSON中的实数被转换为Python的float类型, 整数被转换为int或者long类型. 类似object_hook, 我们可以通过parse_float和parse_int参数指定自定义的转换逻辑. 这两个方法的输入参数为表示JSON实数或者整数的字符串. 下例中, 我们将实数转换为numpy.float64, 将整数转换为numpy.int64:

>>> def my_parse_float(f):
... print('%s(%s)' % (type(f), f))
... return numpy.float64(f)
...
>>> def my_parse_int(i):
... print('%s(%s)' % (type(i), i))
... return numpy.int64(i)
...
>>> result = json.loads('{"i": 123, "f": 321.45}', parse_float=my_parse_float, parse_int=my_parse_int)
<type 'str'>(123)
<type 'str'>(321.45)
>>> type(result['i'])
<type 'numpy.int64'>
>>> type(result['f'])
<type 'numpy.float64'>

2.6.1 自定义NaN, Infinity和-Infinity转换类型

由于标准JSON数据不支持NaN, Infinity和-Infinity, 所以parse_float并不会接收到这几个值. 当需要自定义这几个值转换的对象的时候, 就需要使用另外一个接口parse_constant. 比如下例中, 将这几个值同样转换为numpy.float64类型:

>>> def my_parse_constant(data):
... print('%s(%s)' % (type(data), data))
... return numpy.float64(data)
...
>>> result = json.loads('{"inf": Infinity, "nan": NaN, "ninf": -Infinity}', parse_constant=my_parse_constant)
<type 'str'>(Infinity)
<type 'str'>(NaN)
<type 'str'>(-Infinity)
>>> result['inf']
inf
>>> type(result['inf'])
<type 'numpy.float64'>

2.7 非对象顶级值

根据JSON规范, 一个JSON数据中, 可以只包含一个值, 而不是一个完整的对象. 这个值可以是一个字符串, 一个数字, 布尔值, 空值, 或者一个数组. 除了这三种JSON规范中给出的类型, 还可以是NaN, Infinity或者-Infinity:

>>> json.loads('"hello"')
'hello'
>>> json.loads('123')
123
>>> json.loads('123.34')
123.34
>>> json.loads('true')
True
>>> json.loads('false')
False
>>> print(json.loads('null'))
None
>>> json.loads('[1, 2, 3]')
[1, 2, 3]

2.8 重复键名

在同一层级JSON对象中, 不应当出现重复的键名, 不过JSON规范中没有给出这种情况的处理标准. 在json.loads中, 当JSON数据中有重复键名, 则后面的键值会覆盖前面的:

>>> json.loads('{"a": 123, "b": "ABC", "a": 321}')
{'a': 321, 'b': 'ABC'}

2.9 处理JSON数据文件

当JSON数据是保存在一个文件中的时候, json.load方法可以用来从这个文件中读取数据, 并转换为Python对象. json.load方法的第一个参数就是指向JSON数据文件的文件类型对象.

比如/tmp/data.json文件的内含如下:

{
"a": 123,
"b": "ABC"
}

可以使用下例中的代码来读取并转化文件中的JSON数据:

>>> with open('/tmp/data.json') as jf:
... json.load(jf)
...
{u'a': 123, u'b': u'ABC'}

除了文件类型的对象, 只要是实现了read方法的类文件对象, 都可以作为fp参数, 比如下例中的io.StringIO:

>>> sio = io.StringIO('{"a": 123}')
>>> json.load(sio)
{'a': 123}

json.load方法的其他参数的意义和使用方法和上文中的json.loads相同, 这里不再赘述.

3 生成JSON

json.dumps方法可以将Python对象转换为一个表示JONS数据的字符串. 它的完整接口签名如下:

json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

它的第一个参数obj即为要转换的数据对象.

>>> json.dumps({'a': 123, 'b': 'ABC'})
'{"a": 123, "b": "ABC"}'

3.1 编码格式

json.dumps的ensure_ascii参数用来控制生成的JSON字符串的编码. 其默认值为True, 此时, 所有的非ASCII码字条都会转义. 如果不希望自动进行转义, 则会保持原有编码, 限UTF-8. 如下例所示:

>>> json.dumps({'数字': 123, '字符': '一二三'})
'{"\\u6570\\u5b57": 123, "\\u5b57\\u7b26": "\\u4e00\\u4e8c\\u4e09"}'
>>> json.dumps({'数字': 123, '字符': '一二三'}, ensure_ascii=False)
'{"数字": 123, "字符": "一二三"}'

3.2 数据类型转换

在默认实现中, json.dumps可以处理的Python对象, 及其所有的属性值, 类型必须为dict, list, tuple, str, float或者int. 这些类型与JSON的数据转换关系如下表:

Python JSON
dict object
list, tuple array
str string
int, float, int-&float-derived emuns number
True true
False false
None null

实际转换情况如下示例:

>>> json.dumps(
... {
... 'str': 'ABC',
... 'int': 123,
... 'float': 321.45,
... 'bool_true': True,
... 'bool_false': False,
... 'none': None,
... 'list': [1, 2, 3],
... 'tuple': [12, 34]
... }
... )
'{"str": "ABC", "int": 123, "float": 321.45, "bool_true": true, "bool_flase": false, "none": null, "list": [1, 2, 3], "tuple": [12, 34]}'

虽然JSON标准规范不支持NaN, Infinity和-Infinity, 但是json.dumps的默认实现会将float('nan'), float('inf')和float('-inf')转换为常量NaN, Infinity, 和-Infinity. 如下例所示:

>>> json.dumps(
... {
... 'nan': float('nan'),
... 'inf': float('inf'),
... '-inf': float('-inf')
... }
... )
'{"nan": NaN, "inf": Infinity, "-inf": -Infinity}'

由于这些常量可能会导致生成的JSON字符串不能被其他的JSON实现处理, 为了防止这种情况出现, 可以将json.dumps的allow_nan参数设置为True. 此时, 当处理的Python对象中出现这些值时, json.dumps方法会抛出异常.

3.3 循环引用

json.dumps方法会检查Python对象中是否有循环引用, 如果发现了循环引用, 就会抛出异常. 如下例所示:

>>> circular_obj = {}
>>> circular_obj['self'] = circular_obj
>>> circular_obj
{'self': {...}}
>>> json.dumps(circular_obj)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
ValueError: Circular reference detected

如果不希望json.dumps方法检查循环引用, 可以将参数check_circular设置为False. 但如果此时Python对象中有循环引用, 有可能发生递归嵌套过深的错误或者其他错误, 这么做是比较危险的. 如下例所示:

>>> json.dumps(circular_obj, check_circular=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
RecursionError: maximum recursion depth exceeded while encoding a JSON object

3.4 JSON字符串输出格式

json.dumps方法的indent参数可以用来控制JSON字符串的换行和缩进效果.

indent参数默认值为None. 此时, JSON字符串不会有换行和缩进效果. 如下示:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}))
{"a": 123, "b": {"x": 321, "y": "ABC"}}

当indent为0或者负数时, JSON字符会包含换行:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=-1))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}
>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=0))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}

而当indent为正整数时, 除了换行, JSON还会以指定数量的空格为单位在对象层次间进行缩进:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=2))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}

indent还可以是str, 此时, JSON会以str内容为单位进行缩进, 比如制表符\t:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent='\t'))
{
"a": 123,
"b": {
"x": 321,
"y": "ABC"
}
}

json.dumps的另外一个参数separators可以用来设置输出的分隔符. 这个参数的值应当是一个有两个元素的tuple. 其第一个值为成员间的分隔符, 第二个值为键值之间的分隔符. 其默认值也会随上文中的indent参数影响. 当indent为None时, separators的默认值为(', ', ': '), 即分隔符后都有一个空格. 当indent不为None时, 其默认值则为(',', ':'), 即只有键值间分隔符后会有一个空格, 而元素间分隔符则不带空格, 因为此时会有换行.

separators参数的一种可能的使用场景是希望移除所有的非必要格式字符, 以此来减小JSON字符串的大小. 此时可以将separator设置为(',', ';'), 并不设置indent参数, 或者将其显式设置为None:

>>> print(json.dumps({'a': 123, 'b': {'x': 321, 'y': 'ABC'}}, indent=None, separators=(',', ':')))
{"a":123,"b":{"x":321,"y":"ABC"}}

3.5 转换自定义Python对象

json.dumps的默认实现只能转换Dictionary类型的对象. 如果想要转换自定义对象, 需要使用default参数. 这个参数接收一个函数, 这个函数的参数是一个要转换的Python对象, 返回值是能够表示这个Python对象的Dictionary对象. default函数会从对象引用树的顶层开始, 逐层遍历整个对象引用树. 因此, 不用自己实现对象树的遍历逻辑, 只需要处理当前层次的对象. 如下例所示:

>>> class MyClass:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> def my_default(o):
... if isinstance(o, MyClass):
... print('%s.y: %s' % (type(o), o.y))
... return {'x': o.x, 'y': o.y}
... print(o)
... return o
...
>>> obj = MyClass(x=MyClass(x=1, y=2), y=11)
>>> json.dumps(obj, default=my_default)
<class '__main__.MyClass'>.y: 11
<class '__main__.MyClass'>.y: 2
'{"x": {"x": 1, "y": 2}, "y": 11}'

3.6 非字符串类型键名

在Python中, 只是可哈希(hashable)的对象和数据都可以做为Dictionary对象的键, 而JSON规范中则只能使用字符串做为键名. 所以在json.dumps的实现中, 对这个规则进行了检查, 不过键名允许的范围有所扩大, str, int, float, bool和None类型的数据都可以做为键名. 不过当键名非str的情况时, 键名会转换为对应的str值. 如下例:

>>> json.dumps(
... {
... 'str': 'str',
... 123: 123,
... 321.54: 321.54,
... True: True,
... False: False,
... None: None
... }
... )
'{"str": "str", "123": 123, "321.54": 321.54, "true": true, "false": false, "null": null}'

而当出现其他类型的键名时, 默认出抛出异常:

>>> json.dumps({(1,2): 123})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
TypeError: keys must be a string

json.dumps的skipkeys参数可以改变这个行为. 当将skipkeys设置为True时, 遇到非法的键名类型, 不会抛出异常, 而是跳过这个键名:

>>> json.dumps({(1,2): 123}, skipkeys=True)
'{}'

3.7 生成JSON文件

当需要将生成的JSON数据保存到文件时, 可以使用json.dump方法. 这个方法比json.dumps多了一个参数fp, 这个参数就是用来保存JSON数据的文件对象. 比如, 下例中的代码

>>> with open('/tmp/data.json', mode='a') as jf:
... json.dump({'a': 123}, jf)
...

就会将JSON数据写入到/tmp/data.json文件里. 代码执行完后, 文件内容为

{"a": 123} 
json.dump方法也可以接受其他类文件对象:
>>> sio = io.StringIO()
>>> json.dump({'a': 123}, sio)
>>> sio.getvalue()
'{"a": 123}'

json.dump的其他参数和json.dumps的用法相同, 这里不再赘述.

4 JSON解码和编码类实现

json.loads, json.load, json.dumps和json.dump这四个方法是通过json.JSONDecoder和json.JSONEncoder这两个类来完成各自的任务的. 所以也可以直接使用这两个类来完成前文描述的功能:

>>> json.JSONDecoder().decode('{"a": 123}')
{'a': 123}
>>> json.JSONEncoder().encode({'a': 123})
'{"a": 123}'

json.loads, json.load, json.dumps和json.dump这个四个方法的参数主要都是传递给了json.JSONDecoder和json.JSONEncoder的构造方法, 所以使用这些方法可以满足绝大部分需求. 当需要自定义json.JSONDecoder和json.JSONEncoder子类的时候, 只需要将子类传递给cls参数. 同时, 这些方法都有**kw参数. 当自定义实现类的构造函数需要标准参数列表之外的新参数时, 这个参数就会将新参数传递给实现类的构造方法.

5 相关资源

  1. JSON
  2. The JavaScript Object Notation (JSON) Data Interchange Format - RFC 4627
  3. json — JSON encoder and decoder

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python命令行参数sys.argv使用示例
Jan 28 Python
Python中操作符重载用法分析
Apr 29 Python
Python实现将数据库一键导出为Excel表格的实例
Dec 30 Python
Python发送http请求解析返回json的实例
Mar 26 Python
python简易实现任意位数的水仙花实例
Nov 13 Python
Python面向对象之类和对象属性的增删改查操作示例
Dec 14 Python
python基础知识(一)变量与简单数据类型详解
Apr 17 Python
Python向excel中写入数据的方法
May 05 Python
seek引发的python文件读写的问题及解决
Jul 26 Python
python logging日志模块原理及操作解析
Oct 12 Python
在 Windows 下搭建高效的 django 开发环境的详细教程
Jul 27 Python
你需要掌握的20个Python常用技巧
Feb 28 Python
Python 编码规范(Google Python Style Guide)
May 05 #Python
python 编码规范整理
May 05 #Python
PYTHON基础-时间日期处理小结
May 05 #Python
python 日期操作类代码
May 05 #Python
Python批量发送post请求的实现代码
May 05 #Python
PyQt5 pyqt多线程操作入门
May 05 #Python
详解pyqt5 动画在QThread线程中无法运行问题
May 05 #Python
You might like
Windows下利用Gvim写PHP产生中文乱码问题解决方法
2011/04/20 PHP
Javascript实例教程(19) 使用HoTMetal(7)
2006/12/23 Javascript
javascript getElementsByClassName 和js取地址栏参数
2010/01/02 Javascript
Jquery同辈元素选中/未选中效果的实例代码
2013/08/01 Javascript
javascript运行机制之this详细介绍
2014/02/07 Javascript
JS交换变量的方法
2015/01/21 Javascript
html+js实现简单的计算器代码(加减乘除)
2016/07/12 Javascript
使用Ajax与服务器(JSON)通信实例
2016/11/04 Javascript
node.js版本管理工具n无效的原理和解决方法
2016/11/24 Javascript
js实现增加数字显示的环形进度条效果
2017/02/05 Javascript
实时监控input框,实现输入框与下拉框联动的实例
2018/01/23 Javascript
使用angular-cli webpack创建多个包的方法
2018/10/16 Javascript
基于ssm框架实现layui分页效果
2019/07/27 Javascript
Vue实现图书管理小案例
2020/12/03 Vue.js
javascript代码实现简易计算器
2021/01/25 Javascript
Golang与python线程详解及简单实例
2017/04/27 Python
Django admin美化插件suit使用示例
2017/12/12 Python
Python功能点实现:函数级/代码块级计时器
2019/01/02 Python
python的slice notation的特殊用法详解
2019/12/27 Python
Python面向对象程序设计之私有变量,私有方法原理与用法分析
2020/03/23 Python
python+selenium+chrome批量文件下载并自动创建文件夹实例
2020/04/27 Python
详解HTML5 LocalStorage 本地存储
2016/12/23 HTML / CSS
Ralph Lauren英国官方网站:Ralph Lauren UK
2018/04/03 全球购物
德国最大的服装、鞋子和配件在线商店之一:Outfits24
2019/07/23 全球购物
Linux中如何设置Java环境变量(Ubuntu)
2016/07/24 面试题
食品采购员岗位职责
2014/04/14 职场文书
小学生竞选班长演讲稿
2014/04/24 职场文书
计算机软件专业求职信
2014/06/10 职场文书
战略合作意向书
2014/07/29 职场文书
党的群众路线教育实践活动个人整改方案
2014/09/21 职场文书
2014年银行信贷员工作总结
2014/12/08 职场文书
给老婆的道歉信
2015/01/20 职场文书
《月球之谜》教学反思
2016/02/20 职场文书
导游词之金鞭溪风景区
2019/09/12 职场文书
Win11安全功能升级:内置防网络钓鱼功能
2022/04/08 数码科技
js前端面试常见浏览器缓存强缓存及协商缓存实例
2022/06/21 Javascript