ログや機械学習用のデータなど、JSON ファイルにデータを保存したいが、ファイルに追記で(ファイルの末尾に)追加したい。つまり、JSON 要素を JSON ファイルの末尾に挿入したい。
しかし、ファイルが肥大化していくためファイル全体をメモリに読み込まないで追記できないか。
また、1行1JSON データで完結させて追記しないで JSON 配列に追加したいのです。
{"key0": "one"}
{"key1": "two"}
{"key2": "new!"}
[{"key0": "one"}, {"key1": "two"}, {"key2": "new!"}]
TL;DR
ファイル末尾の「
]
」を削除して JSON 配列を開けてから、「,
」と JSON 要素を追加後、配列を閉じる。
[{"key0": "one"}, {"key1": "two"}]
[{"key0": "one"}, {"key1": "two"}
[{"key0": "one"}, {"key1": "two"}, {"key2": "new!"}
[{"key0": "one"}, {"key1": "two"}, {"key2": "new!"}]
TS;DR
サンプル関数
import json
def append_json_to_file(data: dict, path_file: str) -> bool:
with open(path_file, 'ab+') as f: # ファイルを開く
f.seek(0,2) # ファイルの末尾(2)に移動(フォフセット0)
if f.tell() == 0 : # ファイルが空かチェック
f.write(json.dumps([data]).encode()) # 空の場合は JSON 配列を書き込む
else :
f.seek(-1,2) # ファイルの末尾(2)から -1 文字移動
f.truncate() # 最後の文字を削除し、JSON 配列を開ける(]の削除)
f.write(' , '.encode()) # 配列のセパレーターを書き込む
f.write(json.dumps(data).encode()) # 辞書を JSON 形式でダンプ書き込み
f.write(']'.encode()) # JSON 配列を閉じる
return f.close() # 連続で追加する場合は都度 Open, Close しない方がいいかも
実行例
from functions import append_json_to_file
PATH_FILE = 'test.txt'
for i in range(10):
data = { f'key{i}': i } # サンプル辞書データ(>= Python3.6 f文字列)
append_json_to_file(data, PATH_FILE) # 要素を追加
# 検証(保存ファイルのまるごと読み込み)
f_saved = open(PATH_FILE, "r")
contents = f_saved.read()
print(contents)
f_saved.close()
from functions import append_json_to_file
PATH_FILE = 'test.txt'
for i in range(10):
key = 'key{num}'.format(num=i)
data = { key: i } # サンプル辞書データ
append_json_to_file(data, PATH_FILE) # 要素を追加
# 検証(保存ファイルのまるごと読み込み)
f_saved = open(PATH_FILE, "r")
contents = f_saved.read()
f_saved.close()
print(contents)
実行結果
[{"key0": 0} , {"key1": 1} , {"key2": 2} , {"key3": 3} , {"key4": 4} , {"key5": 5} ,
{"key6": 6} , {"key7": 7} , {"key8": 8} , {"key9": 9}]
- オンラインで動作確認する @ paiza.IO (Python 3.6.6, Ubuntu 18.04.1 LTS)
- macOS HighSierra(Python 3.6.0, OSX 10.13.6)
- RaspberryPi(Python 3.4.2, Raspbian GNU/Linux 8 Jessie)
open(path_file, 'ab+')
の ab+
文字 | 意味 |
---|---|
'r' | 読み込み用に開く (デフォルト) |
'w' | 書き込み用に開き、まずファイルを切り詰める |
'x' | 排他的な生成に開き、ファイルが存在する場合は失敗する |
'a' | 書き込み用に開き、ファイルが存在する場合は末尾に追記する |
'b' | バイナリモード |
't' | テキストモード (デフォルト) |
'+' | ディスクファイルを更新用に開く (読み込み/書き込み) |
- open 関数@ Python3 マニュアルより
Seek
メソッド
fileObject.seek(offset[, from_what])
ファイルオブジェクトの位置を変更するには、
f.seek(offset, from_what)
を使います。ファイル位置は基準点(reference point)にオフセット値offset
を足して計算されます。
参照点はfrom_what
引数で選びます。from_what
の値が0
ならばファイルの 先頭から測り、1
ならば現在のファイル位置を使い、2
ならばファイルの終端を参照点として使います。from_what
は省略することができ、デフォルトの値は0
、すなわち参照点としてファイルの先頭を使います。(「ファイルオブジェクトのメソッド」| 入力と出力 @ Python 3.7 公式ドキュメントより)
参考文献
- 「ファイルオブジェクトのメソッド | 入力と出力」@ Python3 公式ドキュメント
- 「Appending data to a json file in Python @ StackOverflow