json might not be the best choice for on-disk formats; The trouble it has with appending data is a good example of why this might be. Specifically, json objects have a syntax that means the whole object must be read and parsed in order to understand any part of it.
Fortunately, there are lots of other options. A particularly simple one is CSV; which is supported well by python's standard library. The biggest downside is that it only works well for text; it requires additional action on the part of the programmer to convert the values to numbers or other formats, if needed.
Another option which does not have this limitation is to use a sqlite database, which also has built-in support in python. This would probably be a bigger departure from the code you already have, but it more naturally supports the 'modify a little bit' model you are apparently trying to build.
Answer from SingleNegationElimination on Stack Overflowjson might not be the best choice for on-disk formats; The trouble it has with appending data is a good example of why this might be. Specifically, json objects have a syntax that means the whole object must be read and parsed in order to understand any part of it.
Fortunately, there are lots of other options. A particularly simple one is CSV; which is supported well by python's standard library. The biggest downside is that it only works well for text; it requires additional action on the part of the programmer to convert the values to numbers or other formats, if needed.
Another option which does not have this limitation is to use a sqlite database, which also has built-in support in python. This would probably be a bigger departure from the code you already have, but it more naturally supports the 'modify a little bit' model you are apparently trying to build.
You probably want to use a JSON list instead of a dictionary as the toplevel element.
So, initialize the file with an empty list:
with open(DATA_FILENAME, mode='w', encoding='utf-8') as f:
json.dump([], f)
Then, you can append new entries to this list:
with open(DATA_FILENAME, mode='w', encoding='utf-8') as feedsjson:
entry = {'name': args.name, 'url': args.url}
feeds.append(entry)
json.dump(feeds, feedsjson)
Note that this will be slow to execute because you will rewrite the full contents of the file every time you call add. If you are calling it in a loop, consider adding all the feeds to a list in advance, then writing the list out in one go.
How to append an dictionary into a json file?
python - Append JSON to file - Stack Overflow
create and append data in json format to json file - python - Stack Overflow
appending to json file : Forums : PythonAnywhere
Hello I currently learning json in python i want to append a dictionary in a json file ontop of existing ones but every time i do this i get this error in VS-Code:
End of file expected.
Can somebody help me?
Here is the Code:
dict = {
"data1" : data3,
"data2" : data4
}
data = json.dumps(dict)
with open("index.json" , "a") as file:
json.dump(data , file)
I suspect you left out that you're getting a TypeError in the blocks where you're trying to write the file. Here's where you're trying to write:
with open('offline_post.json','a') as f:
new = json.loads(f)
new.update(a_dict)
json.dump(new,f)
There's a couple of problems here. First, you're passing a file object to the json.loads command, which expects a string. You probably meant to use json.load.
Second, you're opening the file in append mode, which places the pointer at the end of the file. When you run the json.load, you're not going to get anything because it's reading at the end of the file. You would need to seek to 0 before loading (edit: this would fail anyway, as append mode is not readable).
Third, when you json.dump the new data to the file, it's going to append it to the file in addition to the old data. From the structure, it appears you want to replace the contents of the file (as the new data contains the old data already).
You probably want to use r+ mode, seeking back to the start of the file between the read and write, and truncateing at the end just in case the size of the data structure ever shrinks.
with open('offline_post.json', 'r+') as f:
new = json.load(f)
new.update(a_dict)
f.seek(0)
json.dump(new, f)
f.truncate()
Alternatively, you can open the file twice:
with open('offline_post.json', 'r') as f:
new = json.load(f)
new.update(a_dict)
with open('offline_post.json', 'w') as f:
json.dump(new, f)
This is a different approach, I just wanted to append without reloading all the data. Running on a raspberry pi so want to look after memory. The test code -
import os
json_file_exists = 0
filename = "/home/pi/scratch_pad/test.json"
# remove the last run json data
try:
os.remove(filename)
except OSError:
pass
count = 0
boiler = 90
tower = 78
while count<10:
if json_file_exists==0:
# create the json file
with open(filename, mode = 'w') as fw:
json_string = "[\n\t{'boiler':"+str(boiler)+",'tower':"+str(tower)+"}\n]"
fw.write(json_string)
json_file_exists=1
else:
# append to the json file
char = ""
boiler = boiler + .01
tower = tower + .02
while(char<>"}"):
with open(filename, mode = 'rb+') as f:
f.seek(-1,2)
size=f.tell()
char = f.read()
if char == "}":
break
f.truncate(size-1)
with open(filename, mode = 'a') as fw:
json_string = "\n\t,{'boiler':"+str(boiler)+",'tower':"+str(tower)+"}\n]"
fw.seek(-1, os.SEEK_END)
fw.write(json_string)
count = count + 1
Quite simply: parse your json to get a Python object, update the python object, and dump it back to json.
import json
with open("myfile.json") as f:
obj = json.load(f)
obj["users"].append({"name":"was that so complicated, really ?"})
with open("myfile.json", "w") as f:
json.dump(f, obj)
I understand this might be a bit less obvious for a beginner, but given json specs, you can easily understand why the only reliable way to modify a json content is to actually parse it. Appending to the file won't work obviously as you already noticed (you'll get invalid json). Trying to read the file line by line, detect the end of the user array and insert a newline here won't work either (or only accidentally) since the json format does not mandate newlines anywhere, so you could as well have everything crammed in one single line ie:
{"users":[{"name":"test"},{"name":"test2"}]}
wrt/ memory comsuption / perfs etc, json is not designed for huge datasets anyway (you want jsonlines or something similar for this) so you shouldn't worry about it - and that's your only option anyway.
Here is a possible solution.
import json
# your string
json_string = '{
"users":
[
{"name" : "test"},
{"name" : "test2"}
]
}'
# convert it to a python dictionary
json_dict = json.loads(json_string)
# append your data as {key:value}
json_dict['users'].append({'name':'test3'})
# convert it back to string
json_string = json.dumps(json_dict)
print (json_string)
Take a look at json lines, its a format that matches what you need
https://jsonlines.org/examples/
In a jsonl file, every line by itself is a valid json, that way you can just
# to read
data = []
with open('my_file.jsonl') as f:
for line in f:
data.append(json.loads(line))
# to write a new line
with open('my_file.jsonl', 'a') as f:
f.write(json.dumps(some_data) + '\n')
That way to can append items to the "array" without reading it first
If you have no control over the json file you start with, but you know it's valid json and it only contains an array (with any content), this works:
import os
import json
some_data = [
1, 2, 3, 4,
"one", "two", "three",
[1, 2, 3],
{1: "one", 2: "two"}, {3: "one", 4: "two"}
]
def append_to_json_arr(fn, data):
end = ''
was_empty = True
with open(fn, 'r+') as f:
f.seek(0, os.SEEK_END)
i = f.tell()
while i >= 0:
f.seek(i)
end += (ch := f.read(1))
if ch == ']':
j = i - 1
while j >= 0:
f.seek(j)
ch = f.read(i)
if ch == '[':
f.seek(i)
break
elif ch.strip():
f.seek(i)
was_empty = False
break
break
i -= 1
json_text = ','.join(json.dumps(item) for item in data)
if not was_empty:
json_text = ',' + json_text
f.write(json_text)
f.write(end)
# starting with an empty one for example
with open('test.json', 'w') as f:
json.dump([], f)
# adding all the data at once
append_to_json_arr('test.json', some_data)
# adding the data again in lists of one item at a time
for item in some_data:
append_to_json_arr('test.json', [item])
What append_to_json_arr does:
- find the end of the file
- read characters from it until you find the end of the array (as it's valid json, and contains an array, you should find a
] - then the first non-whitespace character before it is a
[for an empty list, or anything else if the list contains something - write the new elements over the end of the list, then rewrite the end.
For a more robust function, you may want to deal with malformed files, or perhaps with files that have json, but not a list.