130

I have a python web form with two options - File upload and textarea. I need to take the values from each and pass them to another command-line program. I can easily pass the file name with file upload options, but I am not sure how to pass the value of the textarea.

I think what I need to do is:

  1. Generate a unique file name
  2. Create a temporary file with that name in the working directory
  3. Save the values passed from textarea into the temporary file
  4. Execute the commandline program from inside my python module and pass it the name of the temporary file

I am not sure how to generate a unique file name. Can anybody give me some tips on how to generate a unique file name? Any algorithms, suggestions, and lines of code are appreciated.

Thanks for your concern

1
  • 1
    I edited your question to try and make it more clear. Let me know if I interpreted something incorrectly! Commented Sep 1, 2012 at 10:12

9 Answers 9

189

I didn't think your question was very clear, but if all you need is a unique file name...

import uuid

unique_filename = str(uuid.uuid4())
Sign up to request clarification or add additional context in comments.

6 Comments

Sorry i am working on windows platform so dont know how to handle subprocess
uuid seems to create a long unique string. I dont think its better to have file name with long string and UUID, () in it.
I think uuid.uuid4().hex would be a better choice, see detail here.
@ToloPalmer: It's more likely that your computer's CPU has a processing error that causes it to load the wrong file than it is a generated UUID collides with any existing value. UUID produces a unique name in a model of computing that understands not all computation is pure mathematics.
Pardon my ignorance old comment... Indeed is not unique but very unlikely to collide, so good choice ;)
|
65

The uuid module would be a good choice, I prefer to use uuid.uuid4().hex as random filename because it will return a hex string without dashes.

import uuid
filename = uuid.uuid4().hex

The outputs should like this:

>>> import uuid
>>> uuid.uuid()
UUID('20818854-3564-415c-9edc-9262fbb54c82')
>>> str(uuid.uuid4())
'f705a69a-8e98-442b-bd2e-9de010132dc4'
>>> uuid.uuid4().hex
'5ad02dfb08a04d889e3aa9545985e304'  # <-- this one

3 Comments

What's the problem of having dashes?
Is it aesthetics or there's another reason for adding .hex?
Normally you would use the dashes to separate words in a filename (e.g. my-favorite-shoes.jpg). However, if the filename is randomly generated, I would prefer a filename without dashes, it's more beautiful, and the dashes here are meaningless.
59

If you want to make temporary files in Python, there's a module called tempfile in Python's standard libraries. If you want to launch other programs to operate on the file, use tempfile.mkstemp() to create files, and os.fdopen() to access the file descriptors that mkstemp() gives you.

Incidentally, you say you're running commands from a Python program? You should almost certainly be using the subprocess module.

So you can quite merrily write code that looks like:

import subprocess
import tempfile
import os

(fd, filename) = tempfile.mkstemp()
try:
    tfile = os.fdopen(fd, "w")
    tfile.write("Hello, world!\n")
    tfile.close()
    subprocess.Popen(["/bin/cat", filename]).wait()        
finally:
    os.remove(filename)

Running that, you should find that the cat command worked perfectly well, but the temporary file was deleted in the finally block. Be aware that you have to delete the temporary file that mkstemp() returns yourself - the library has no way of knowing when you're done with it!

(Edit: I had presumed that NamedTemporaryFile did exactly what you're after, but that might not be so convenient - the file gets deleted immediately when the temp file object is closed, and having other processes open the file before you've closed it won't work on some platforms, notably Windows. Sorry, fail on my part.)

7 Comments

using NamedTemporaryFile is probably what they want (unless they want it to stay on the server, and then they can use "tempfile.NamedTemporaryFile(delete=False)")
Can i make that temporary file name unique too ? so i can save it later when subprocess is completed with unique name
@Terence Honles: I'd suggested tempfile.NamedTemporaryFile() originally, but you can't really use that to make temporary files that other processes can access on Windows. NamedTemporaryFile(delete=False) certainly is cleaner, though. @user343934: tempfile.mkstemp() is guaranteed to give you a unique name each time it's called - it generates the names randomly and it uses the OS facilities (O_EXCL, if you're wondering) to avoid collisions.
wow I didn't know it doesn't work on windows... fail :( ...I guess that's good to know
@Terence Honles: NamedTemporaryFile() doesn't actually fail on Windows (as far as I know), but you can't close file without deleting it too, and (as I understand file semantics on Windows) no other program can open the file while you have it open. I might be wrong; the semantics for having multiple processes sharing a file under Windows might have changed since I last checked.
|
21

Maybe you need unique temporary file?

import tempfile

f = tempfile.NamedTemporaryFile(mode='w+b', delete=False)

print f.name
f.close()

f is opened file. delete=False means do not delete file after closing.

If you need control over the name of the file, there are optional prefix=... and suffix=... arguments that take strings. See https://docs.python.org/3/library/tempfile.html.

3 Comments

This is great if you don't need to control the name of the file.
It should be tmpfile.NamedTemporaryFile not just NamedTemporaryFile.
w+b is the default mode. Using any tempfile functionality has the disadvantage of incorrect file access permissions: tempfile documents to use os.O_TMPFILE as mask, but normal file creation respects os.umask().
15

You can use the datetime module

import datetime
uniq_filename = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')

Note that: I am using replace since the colons are not allowed in filenames in many operating systems.

That's it, this will give you a unique filename every single time.

1 Comment

Unless the file names are created immediately after each other (e.g. in a loop). Then they're the same.
9

In case you need short unique IDs as your filename, try shortuuid, shortuuid uses lowercase and uppercase letters and digits, and removing similar-looking characters such as l, 1, I, O and 0.

>>> import shortuuid
>>> shortuuid.uuid()
'Tw8VgM47kSS5iX2m8NExNa'
>>> len(ui)
22

compared to

>>> import uuid
>>> unique_filename = str(uuid.uuid4())
>>> len(unique_filename)
36
>>> unique_filename
'2d303ad1-79a1-4c1a-81f3-beea761b5fdf'

Comments

1

I came across this question, and I will add my solution for those who may be looking for something similar. My approach was just to make a random file name from ascii characters. It will be unique with a good probability.

from random import sample
from string import digits, ascii_uppercase, ascii_lowercase
from tempfile import gettempdir
from os import path

def rand_fname(suffix, length=8):
    chars = ascii_lowercase + ascii_uppercase + digits

    fname = path.join(gettempdir(), 'tmp-'
                + ''.join(sample(chars, length)) + suffix)

    return fname if not path.exists(fname) \
                else rand_fname(suffix, length)

3 Comments

The obvious answer for the question had to do with the uuid package. However my target server has python 2.4, no uuid package and upgrading was not authorized by server owner due to legacy software incompatibilities, so this answer works for me.
I particularly like this answer: can be easily tweaked to project specs.
1) There's no reason to use recursion here, especially unbounded. 2) There exists race condition between the time that path.exists() returns False and the time that a consumer actually opens the file.
1

This can be done using the unique function in ufp.path module.

import ufp.path
ufp.path.unique('./test.ext')

if current path exists 'test.ext' file. ufp.path.unique function return './test (d1).ext'.

1 Comment

ufp is part of drupal? not a standard module
1

To create a unique file path if its exist, use random package to generate a new string name for file. You may refer below code for same.

import os
import random
import string

def getUniquePath(folder, filename):    
    path = os.path.join(folder, filename)
    while os.path.exists(path):
         path = path.split('.')[0] + ''.join(random.choice(string.ascii_lowercase) for i in range(10)) + '.' + path.split('.')[1]
    return path

Now you can use this path to create file accordingly.

1 Comment

The file still has a chance of randomizing an existing name.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.