0

I'm not sure if my json file is unique but I couldn't find any other question/answers that worked.

My JSON file looks like:

{"UserID": "name1", "Timestamp": "1234"}
{"UserID": "name2", "Timestamp": "4321"}
{"UserID": "name3", "Timestamp": "1234"}

Is there a way for python to delete an entire line from the file?

This is what I've done so far:

open_file = open("times.json", 'r')
line = open_file.readline()

while line:
    jsonLine = json.loads(line)

    if line['Timestamp'] == '1234':
        del line

open_file.close()

If the timestamp is 1234, I want it to delete the entire object so the file will just look like this:

{"UserID": "name2", "Timestamp": "4321"}

Thanks!

chakolatemilk
  • 833
  • 9
  • 21
  • 31
  • 2
    That's *not* a JSON file. In general, deleting a line from a file is not straightforward - I'd recommend reading the whole file, modifying it in-memory then writing out back over it. – jonrsharpe Jan 10 '19 at 19:46
  • Possible duplicate of [using Python for deleting a specific line in a file](https://stackoverflow.com/questions/4710067/using-python-for-deleting-a-specific-line-in-a-file) – Marcus Jan 10 '19 at 19:46
  • 1
    @jonrsharpe While it's not exactly a JSON file, it is however a proper [JSON lines](http://jsonlines.org/examples/) format. – r.ook Jan 10 '19 at 20:06

3 Answers3

3

Combining both jonrsharpe's and ajon's suggestions, instead of deleting it while reading, read it into memory and then write it back.

You might however have an easier time to read the jsons first and then eliminate the lines with matched elements, instead of manipulating the text directly:

json_lines = []
with open("times.json", 'r') as open_file:
    for line in open_file.readlines():
        j = json.loads(line)
        if not j['Timestamp'] == '1234':
            json_lines.append(line)

with open("times.json", 'w') as open_file:
    open_file.writelines('\n'.join(json_lines))

This method gives you more conditional flexibility over multiple keys/values if necessary as opposed to looking specifically for "TimeStamp": "1234" within the line.

r.ook
  • 13,466
  • 2
  • 22
  • 39
  • This one was exactly what I was looking for. Thank you so much. I had to modify it a bit, but this was perfect. – chakolatemilk Jan 10 '19 at 20:55
  • 1
    I've slightly modified the answer to provide the newline as well. Instead of saving the `json` object for each line, since you're writing the `str` back, just save the `line` from the get go and do a `'\n'.join(...)` after. See my updated answer. – r.ook Jan 10 '19 at 20:57
  • Thank you! Your answer is very helpful. – chakolatemilk Jan 10 '19 at 21:40
  • [`writelines`](https://docs.python.org/3/library/io.html#io.IOBase.writelines) expects a *sequence* of lines; if you build the whole file string yourself, I think it'll write every *character* to a new line. – jonrsharpe Jan 10 '19 at 22:26
  • @jonrsharpe I just read the documentation again, I thought I had missed something but no, the line separator is not added so it was expected within the lists themselves. Seems rather pointless to me since in this case I'd have to `'\n'.join(json_lines)` myself either way if I use `write` or `writelines`. But I agree, in this case probably better if I just used `write()`. – r.ook Jan 11 '19 at 14:43
1

As suggested by @jonrsharpe, you can read in the file. Do whatever manipulations you want. Then rewrite the file.

Here is an example:

test.out:

test file
#test comment
testfile

Python code:

content = ''
with open('test.out', 'r') as f:
  for line in f:
    if line.startswith('#'): continue # don't copy comment lines
    content += line

with open('test.out', 'w') as f:
  f.write(content)

test.out after:

test file
testfile
ajon
  • 7,868
  • 11
  • 48
  • 86
0

Reading the whole file into memory may lead to troubles with large files. You may want to write to a temporary file and then overwrite the old file with the new file. There is a build in python library for that: https://docs.python.org/3/library/tempfile.html

If you are sure, your file is not large, you do not need read_line you can directly use json.load().

phylogram
  • 123
  • 7