# 【Python 筆記】JSON 格式讀寫
[TOC]
感謝您點進本篇文章,我是 LukeTseng,該系列主要以筆記加上口語白話形式學習 Python,若文章某處有誤敬請告知,非常感謝。
## JSON 是啥?
JSON 全名是 **J**ava**S**cript **O**bject **N**otation,這是一種輕量級的資料交換格式,以純文字方式儲存和傳輸資料。雖然名字有 javascript,但他完全獨立於這個程式語言,幾乎所有現代程式語言都支援 JSON 格式。
JSON 的語法很簡單,與 Python 中的字典相似,同樣是採用鍵值對(key-value)的方式組織資料。
JSON 由兩個主要結構組成:
1. 物件(Object)使用大括號 `{}` 包起來,含鍵值對。
2. 陣列(Array)使用中括號 `[]` 包裹,含有序的值列表。
### JSON 的資料型態
JSON 支援六種資料型態,分為簡單型態和複雜型態:
- 簡單型態:
- 字串(string):必須用雙引號包裹,如 `"name": "LukeTseng"`。
- 數字(Number):可為整數或浮點數,如 `"age": 25` 或 `"price": 99.9`。
- 布林值(Boolean):只能是 `true` 或 `false`,不需要引號。
- 空值(Null):表示空值,使用 `null`。
- 複雜類型:
- 物件(Object):無序的鍵值對集合,用大括號 `{}` 包起來。
- 陣列(Array):有序的值集合,用中括號 `[]` 包起來。
### JSON 的範例
取自:https://json.org/example.html
```
{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}
}
```
## JSON in Python
Python 本身就有內建 JSON 的套件,使用 `import json` 這行程式碼即可使用。
這個套件主要就用到以下這四個函式:
1. `json.dumps()`:將 Python **物件**轉換成 JSON 字串。
2. `json.loads()`:將 JSON **字串**轉換成 Python 物件。
3. `json.dump()`:將 Python **物件**寫入 JSON 檔案。
4. `json.load()`:從 JSON 檔案讀取資料到 Python 物件。
上面四個函式其實是兩個函式,因為你會發現 dump 加一個 s 就是字串的意思。
下表關聯了 JSON 資料型態跟 Python 物件的關係:
| Python | JSON |
| -------- | -------- |
| 字典(Dict) | 物件(Object) |
| 列表(List) | 陣列(Array) |
| 字串(String) | 字串(String) |
| 數字(Number) | 數字(Number) |
| True/False | true/false |
| None | null |
### 1. json.dumps()
語法:
```python
json.dumps(obj, skipkeys=False, ensure_ascii=True,
allow_nan=True, indent=None, separators=None,
sort_keys=False)
```
- obj:要轉換的 Python 物件(字典、列表、字串等)。
- skipkeys:跳過不可序列化的 key,而非引發錯誤。
- ensure_ascii:如果為 True(預設值),則跳脫(Escape)非 ASCII 字元;設為 False 則保留它們。
- allow_nan:允許特殊浮點數值(NaN、Infinity)。
- indent:縮排,可指定為某個數值。
- separators:更改預設分隔符號。
- sort_keys:按照字典序對字典鍵進行排序
範例(Python 字典轉 JSON):
```python=
import json
# Python Dict
student = {
"name": "LukeTseng",
"age": 18,
"gpa": 4.3,
"courses": ["演算法", "資料結構", "作業系統"],
"level" : "SSR",
}
# 轉換成 JSON 字串
json_string = json.dumps(student)
print(json_string)
```
Output:
```
{"name": "LukeTseng", "age": 18, "gpa": 4.3, "courses": ["\u6f14\u7b97\u6cd5", "\u8cc7\u6599\u7d50\u69cb", "\u4f5c\u696d\u7cfb\u7d71"], "level": "SSR"}
```
看來輸出遇到編碼問題了,那這時候只要把 `ensure_ascii = False` 就好了,因為他預設是開著的,所以會自動把非 ASCII 字元給轉成 Unicode 編碼。
再試一次:
```python=
import json
# Python Dict
student = {
"name": "LukeTseng",
"age": 18,
"gpa": 4.3,
"courses": ["演算法", "資料結構", "作業系統"],
"level" : "SSR",
}
# 轉換成 JSON 字串
json_string = json.dumps(student, ensure_ascii=False)
print(json_string)
```
Output:
```
{"name": "LukeTseng", "age": 18, "gpa": 4.3, "courses": ["演算法", "資料結構", "作業系統"], "level": "SSR"}
```
你會看到輸出是一行的,這時候可以用 indent 參數調整縮排,讓結果美化:
```python=
import json
# Python Dict
student = {
"name": "LukeTseng",
"age": 18,
"gpa": 4.3,
"courses": ["演算法", "資料結構", "作業系統"],
"level" : "SSR",
}
# 轉換成 JSON 字串
json_string = json.dumps(student, ensure_ascii=False, indent=4)
print(json_string)
```
Output:
```
{
"name": "LukeTseng",
"age": 18,
"gpa": 4.3,
"courses": [
"演算法",
"資料結構",
"作業系統"
],
"level": "SSR"
}
```
### 2. json.loads()
語法:
```
json.loads(s)
```
- `s`:有效的 JSON 字串(可為 str、bytes 或 bytearray 類型)
範例:
```python=
import json
# 收到的 JSON 字串
json_data = """
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}
"""
# 轉成 Python 字典
menu = json.loads(json_data)
print(menu)
print(menu['menu']['id']) # file
print(type(menu)) # <class 'dict'>
```
Output:
```
{'menu': {'id': 'file', 'value': 'File', 'popup': {'menuitem': [{'value': 'New', 'onclick': 'CreateNewDoc()'}, {'value': 'Open', 'onclick': 'OpenDoc()'}, {'value': 'Close', 'onclick': 'CloseDoc()'}]}}}
file
<class 'dict'>
```
### 3. json.dump()
語法同 `json.dumps()`。
範例:
```python=
import json
# 準備要儲存的資料
students = [
{"name": "LukeTseng", "score": 100},
{"name": "陳圈翔", "score": 87},
{"name": "楊1停", "score": 11}
]
# 寫入檔案
with open('students.json', 'w', encoding='utf-8') as file:
json.dump(students, file, indent=4, ensure_ascii=False)
```
若目錄沒有檔案的話會自動生成一份檔案,有的話則會覆寫整個檔案。
結果(`students.json`):
```jsonld=
[
{
"name": "LukeTseng",
"score": 100
},
{
"name": "陳圈翔",
"score": 87
},
{
"name": "楊1停",
"score": 11
}
]
```
### 4. json.load()
語法同 `json.loads()`。
範例:
沿用上一份範例生成的 `students.json`。
```python=
import json
# 讀取檔案
with open('students.json', 'r', encoding='utf-8') as file:
students = json.load(file)
print(students)
for student in students:
print(f"{student['name']} 的分數是 {student['score']}")
```
Output:
```
[{'name': 'LukeTseng', 'score': 100}, {'name': '陳圈翔', 'score': 87}, {'name': '楊1停', 'score': 11}]
LukeTseng 的分數是 100
陳圈翔 的分數是 87
楊1停 的分數是 11
```
## 總結
JSON 由兩個主要結構組成:物件(Object)使用大括號 `{}` 包起來,以及陣列(Array)使用中括號 `[]` 包起來。
JSON 支援六種資料型態:
簡單型態:
* 字串(String):必須用雙引號包裹,如 `"name": "LukeTseng"`
* 數字(Number):可為整數或浮點數
* 布林值(Boolean):只能是 `true` 或 `false`
* 空值(Null):表示空值,使用 `null`
複雜型態:
* 物件(Object):無序的鍵值對集合。
* 陣列(Array):有序的值集合。
### Python 的 JSON 套件
Python 內建的 json 套件提供四個主要函式:
* json.dumps():將 Python 物件轉換成 JSON 字串(s 代表 string)
* json.loads():將 JSON 字串轉換成 Python 物件
* json.dump():將 Python 物件寫入 JSON 檔案
* json.load():從 JSON 檔案讀取資料到 Python 物件
Python 物件對應 JSON 資料型態關係:
| Python | JSON |
| -------- | -------- |
| 字典(Dict) | 物件(Object) |
| 列表(List) | 陣列(Array) |
| 字串(String) | 字串(String) |
| 數字(Number) | 數字(Number) |
| True/False | true/false |
| None | null |
`json.dumps()` or `json.dump()` 常用參數:
* `ensure_ascii`:預設為 True 會跳脫非 ASCII 字元,設為 False 可保留中文字元
* `indent`:設定縮排數值,美化輸出格式
* `sort_keys`:按字典序排序鍵
* `skipkeys`:跳過不可序列化的鍵
## 參考資料
[json.loads() in Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/json-loads-in-python/)
[json.dumps() in Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/json-dumps-in-python/)
[Python3 JSON 数据解析 | 菜鸟教程](https://www.runoob.com/python3/python3-json.html)
[JSON with Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/json-with-python/)
[JSON 檔案操作 - Python 教學 | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/library/json.html)
[JSON Example](https://json.org/example.html)