#はじめに
pythonでjson形式でファイル保存するとき,次のようにdump関数を使います.
例として,毎日の体重を記録するjsonファイルを想定します.
import json
# 体重をdict形式に入れる
weight_dict = {'date': '2021-01-01', 'weight': 58.3}
filename = 'weight.json'
with open(filename, 'w') as f:
json.dump(weight_dict, f)
{"date": "2021-01-01", "weight": 58.3}
その後,jsonファイルにさらにデータを追記したい,となったとき,どうすればよいでしょうか.
例えば,次の日の体重データを同じjsonファイルに追記したい,という場合を考えてみましょう.
対策として次のような方法があります.
#対策1:単純に追記する
上のコード実行後に次のように実行します.
weight_dict = {'date': '2021-01-02', 'weight': 58.5}
filename = 'weight.json'
with open(filename, 'a') as f:
json.dump(weight_dict, f)
{"date": "2021-01-01", "weight": 58.3}{"date": "2021-01-02", "weight": 58.5}
これでもよいのですが,これでは正しいjsonファイル形式になりません.
というのも,
[{"date": "2021-01-01", "weight": 58.3}, {"date": "2021-01-02", "weight": 58.5}]
なら正しい形式となるのですが,2つの(pythonでいう)辞書形式を並べただけでは,正しくなく,jsonファイルとして読み込みできません.
試しに次のようなコードを実行すると,エラーが生じます.
with open(filename, 'r') as f:
read_data = json.load(f)
JSONDecodeError: Extra data: line 1 column 39 (char 38)
次のようにごり押しをすればいけないこともないですが,数値データが文字列になっています.
with open(filename, 'r') as f:
read_data_str = f.read()
read_data = "[" + read_data_str.replace("\n", "").replace("}{", "},{") + "]"
dict_data = eval(read_data)
print(dict_data)
[{'date': '2021-01-01', 'weight': 58.3},
{'date': '2021-01-02', 'weight': 58.5}]
#対策2:いったんファイルをすべて読みこませてから再度書き込む
はじめに,で実行したコードの後に,以下のようなコードを実行します.
weight_dict = {'date': '2021-01-02', 'weight': 58.5}
with open(filename, 'r') as f:
read_data = json.load(f)
save_data = [read_data, weight_dict]
with open(filename, 'w') as f:
json.dump(save_data, f)
[{"date": "2021-01-01", "weight": 58.3}, {"date": "2021-01-02", "weight": 58.5}]
となり,正しいデータを追記することができました!
もちろん,この方法で問題ないですし,今回の例だったら問題ないのですが,jsonファイルのファイルサイズが大型な場合,読み込み処理に時間がかかってしまいます.
#対策3:ndjsonを使う!
ここで,json形式を使うのではなく,jsonライクな形式を使おうと考えます.
対策1では,json形式をそのまま追記していました.この方法を少し変えて,
json形式を追記するが,それぞれのデータ間に改行\nを加えるというのがndjson形式です.
ちなみにjson line形式とも呼ばれているそうです.
つまり,次のようなjsonライクなファイルで保存します.
{"date": "2021-01-01", "weight": 58.3}
{"date": "2021-01-02", "weight": 58.5}
対策1で作成したjsonファイルとの違いは,改行しているかどうか,だけてす.
また,ファイルに追記するときも,改行コードとデータをただただ末尾に追記するだけなので,すべてのデータを読み込み→追記→書き込み,をする必要はありません.
使用方法は簡単,pythonではndjsonというそのまんまのパッケージがあるので,それを使うだけです.
公式ドキュメント
pip install ndjson
import ndjson
filename = 'weight.ndjson'
# 体重をdict形式に入れる
weight_dict = {'date': '2021-01-01', 'weight': 58.3}
with open(filename, 'a') as f:
writer = ndjson.writer(f)
writer.writerow(weight_dict)
# 追記したいデータ
weight_dict = {'date': '2021-01-02', 'weight': 58.5}
with open(filename, 'a') as f:
writer = ndjson.writer(f)
writer.writerow(weight_dict)
{"date": "2021-01-01", "weight": 58.3}
{"date": "2021-01-02", "weight": 58.5}
読みこみもできます.
with open(filename) as f:
data = ndjson.load(f)
[{'date': '2021-01-01', 'weight': 58.3}, {'date': '2021-01-02', 'weight': 58.5}]
今回紹介した例では,2つのデータだけだったので,ndjsonを使うメリットがあまり実感出来なかったかもしればせんが,
例えば,for文を使って事前に長さの分からない大量のデータを書き込む場合,while True文を使って,1分おきに特定のサイトからデータを取得し,記録する,といった使い方をするときに便利です.