8

I am writing a program which stores some JSON-encoded data in a file, but sometimes the resulting file is blank (because there wasn't found any new data). When the program finds data and stores it, I do this:

with open('data.tmp') as f:
    data = json.load(f)
os.remove('data.tmp')

Of course, if the file is blank this will raise an exception, which I can catch but does not let me to remove the file. I have tried:

try:
    with open('data.tmp') as f:
        data = json.load(f)
except:
    os.remove('data.tmp')

And I get this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "MyScript.py", line 50, in run
    os.remove('data.tmp')
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process

How could I delete the file when the exception occurs?

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
bitomic
  • 170
  • 9
  • It looks like you need to close the file before removing it - try not using `with` and add `f.close()` before `os.remove` in the `except` statement – Adam Jan 05 '19 at 20:50
  • 2
    @Adam: That may not work unless there's a `finally` block that also closes the file, or somesuch. But yeah, the file must be closed before it can be removed. – Robert Harvey Jan 05 '19 at 20:50
  • I already tried doing that. Wrote a `f.close()` before the `os.remove`, but it keeps raising the same exception on the same line (on the `os.remove` sentence) – bitomic Jan 05 '19 at 20:51
  • 1
    Is it being used by another program? – iz_ Jan 05 '19 at 20:51
  • So should I write the `f.close()` inside the `except` block and remove it in the `finally`? – bitomic Jan 05 '19 at 20:52
  • @Tomothy32 Nope, it is only being used by this script. – bitomic Jan 05 '19 at 20:52
  • did you try writing the try-except inside the with open block? you may as well do f.close first in the except block. – Shariq Jan 05 '19 at 20:56
  • @Shariq I did, the result is the same. Even if I just pass the exception and try to remove the file after the `with` statement, it raises the same exception. I think it isn't closing the file, but I can't even close it explicitly... – bitomic Jan 05 '19 at 20:59
  • I tried your code, create data.tmp, put a json inside it, ran the program, works. Then removed the json so the file is blank, still works. json.load(f) doesn't give any error when the file is blank. – Shariq Jan 05 '19 at 21:02
  • @Shariq doesn't it raise a `json.decoder.JSONDecodeError` when a blank file is passed to `json.load`? Because it does when I try it. – bitomic Jan 05 '19 at 21:08
  • Oh well my bad, I couldnt come across the error because it was inside try-except, and the file could be deleted successfuly without the error you're facing. Running Win10, the tmp file & python code placed on desktop – Shariq Jan 05 '19 at 21:15
  • Your second attempt with the try-except works properly for me. It ideally **shouldn't** raise an error. The context manager is properly closing the file here, you probably forgot to close the file when you opened it before in write mode or at some other place in your code. – Abdul Aziz Barkat Feb 23 '23 at 06:10

3 Answers3

2

How about separating out file reading and json loading? json.loads behaves exactly same as json.load but uses a string.

with open('data.tmp') as f:
    dataread = f.read()
os.remove('data.tmp')

#handle exceptions as needed here...
data = json.loads(dataread)
JL Peyret
  • 10,917
  • 2
  • 54
  • 73
  • This works perfectly! This always removes the file, and I can treat the `json.decoder.JSONDecodeError` away from the `with` statement. Thanks! – bitomic Jan 05 '19 at 21:51
1

I am late to the party. But the json dump and load modules seem to keep using files even after writing or reading data from them. What you can do is use dumps or loads modules to get the string representation and then use normal file.write() or file.read() on the result.

For example:

with open('file_path.json'), 'w') as file:
    file.write(json.dumps(json_data))

os.remove('file_path.json')

Not the best alternative but it saves me a lot especially when using temp dir.

0

you need to edit the remove part, so it handles the non-existing case gracefully.

import os
try:
    fn = 'data.tmp'
    with open(fn) as f:
        data = json.load(f)
except:
    try:
        if os.stat(fn).st_size > 0:
            os.remove(fn) if os.path.exists(fn) else None
    except OSError as e: # this would be "except OSError, e:" before Python 2.6
        if e.errno != errno.ENOENT:
            raise

see also Most pythonic way to delete a file which may not exist

you could extract the silent removal in a separate function.

also, from the same other SO question:

# python3.4 and above
import contextlib, os

try:
    fn = 'data.tmp'
    with open(fn) as f:
        data = json.load(f)
except:
    with contextlib.suppress(FileNotFoundError):
        if os.stat(fn).st_size > 0:
            os.remove(fn)

I personally like the latter approach better - it's explicit.

Jörg Beyer
  • 3,631
  • 21
  • 35
  • The same exception occurs :\ – bitomic Jan 05 '19 at 20:56
  • As a note, the file is always granted to exist, so the problem won't be about trying to remove an inexistent file... I think I'll just have to read the file and delete it if hasn't content (aka, is blank), but I would like to have a method handling the exception in case I try to parse JSON data saved incorrectly. – bitomic Jan 05 '19 at 21:04
  • 1
    ok, you can check it like this: os.stat(fn).st_size > 0 Does that help, @Bitom ? – Jörg Beyer Jan 05 '19 at 21:07
  • I think I will use this, since I can't find any other way. I'll wait for other answers, if none could help I'll mark this as the answer. Thanks! ^^ – bitomic Jan 05 '19 at 21:10