72

I want to use tempfile.NamedTemporaryFile() to write some contents into it and then open that file. I have written following code:

tf = tempfile.NamedTemporaryFile()
tfName = tf.name
tf.seek(0)
tf.write(contents)
tf.flush()

but I am unable to open this file and see its contents in Notepad or similar application. Is there any way to achieve this? Why can't I do something like:

os.system('start notepad.exe ' + tfName)

at the end.

I don't want to save the file permanently on my system. I just want the contents to be opened as a text in Notepad or similar application and delete the file when I close that application.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Manoj
  • 819
  • 1
  • 9
  • 9

3 Answers3

78

This could be one of two reasons:

Firstly, by default the temporary file is deleted as soon as it is closed. To fix this use:

tf = tempfile.NamedTemporaryFile(delete=False)

and then delete the file manually once you've finished viewing it in the other application.

Alternatively, it could be that because the file is still open in Python Windows won't let you open it using another application.

Edit: to answer some questions from the comments:

As of the docs from 2 when using delete=False the file can be removed by using:

 tf.close()
 os.unlink(tf.name)
rkachach
  • 16,517
  • 6
  • 42
  • 66
David Webb
  • 190,537
  • 57
  • 313
  • 299
  • 41
    So what is the best way to remove it when I'm done with it? `tf.unlink`? `os.remove`? `path.remove`? – Thomas Ahle Mar 09 '14 at 17:35
  • 1
    @ThomasAhle What would you use? – Martin Thoma Nov 22 '14 at 11:52
  • You need add the import: `import tempfile` to use. – GIA Jul 07 '17 at 19:07
  • 14
    If I use delete=False, but use the context manager (with tempfile.NamedTemporaryFile() as temp:), will it still delete the file when it goes out of scope (as opposed to when it is closed), or do I still have to delete it manually? – JoeMjr2 Mar 08 '19 at 20:31
75

You can also use it with a context manager so that the file will be closed/deleted when it goes out of scope. It will also be cleaned up if the code in the context manager raises.

import tempfile
with tempfile.NamedTemporaryFile() as temp:
    temp.write('Some data')
    temp.flush()

    # do something interesting with temp before it is destroyed
Jay Prall
  • 5,295
  • 5
  • 49
  • 79
  • 15
    Keep in mind that you can't really pass `temp.name` to other processes to do something with it on Windows (which seems to be OP's platform). From the manual: "Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later)." – Vegard Apr 16 '14 at 07:23
  • 1
    Not sure if it would help in any way, but Django overwrote the NamedTemporaryFile so it would work with Windows so it might be worth looking at what they did to make that happen: https://code.djangoproject.com/wiki/NamedTemporaryFile – vjimw Jul 02 '15 at 18:33
  • 6
    It appears that calling `flush` is necessary (Otherwise, I get an error in a subprocess called to read from the file). – 0 _ Aug 27 '15 at 07:25
  • 1
    Flush won't write the file to disk necessarily – Shrey Apr 18 '17 at 08:49
  • 6
    You should use `with tempfile.NamedTemporaryFile(mode='w+t') as temp:` so that you can actually write string text to the file. What you have now opens the temp file in binary mode. – Fitzy Apr 30 '20 at 00:39
25

Here is a useful context manager for this. (In my opinion, this functionality should be part of the Python standard library.)

# python2 or python3
import contextlib
import os

@contextlib.contextmanager
def temporary_filename(suffix=None):
  """Context that introduces a temporary file.

  Creates a temporary file, yields its name, and upon context exit, deletes it.
  (In contrast, tempfile.NamedTemporaryFile() provides a 'file' object and
  deletes the file as soon as that file object is closed, so the temporary file
  cannot be safely re-opened by another library or process.)

  Args:
    suffix: desired filename extension (e.g. '.mp4').

  Yields:
    The name of the temporary file.
  """
  import tempfile
  try:
    f = tempfile.NamedTemporaryFile(suffix=suffix, delete=False)
    tmp_name = f.name
    f.close()
    yield tmp_name
  finally:
    os.unlink(tmp_name)

# Example:
with temporary_filename() as filename:
  os.system('echo Hello >' + filename)
  assert 6 <= os.path.getsize(filename) <= 8  # depending on text EOL
assert not os.path.exists(filename)
Hugues
  • 2,865
  • 1
  • 27
  • 39