81

I don't necessarily want to use UUIDs since they are fairly long.

The file just needs to be unique within its directory.

One thought which comes to mind is to use File.createTempFile(String prefix, String suffix), but that seems wrong because the file is not temporary.

The case of two files created in the same millisecond needs to be handled.

1
  • 5
    Don't pay too much attention to "Temp" part of the name; read javadocs to see that it's really more about uniqueness, which is often needed for temp files. But not necessarily just for them. Commented May 5, 2009 at 16:50

16 Answers 16

98

Well, you could use the 3-argument version: File.createTempFile(String prefix, String suffix, File directory) which will let you put it where you'd like. Unless you tell it to, Java won't treat it differently than any other file. The only drawback is that the filename is guaranteed to be at least 8 characters long (minimum of 3 characters for the prefix, plus 5 or more characters generated by the function).

If that's too long for you, I suppose you could always just start with the filename "a", and loop through "b", "c", etc until you find one that doesn't already exist.

Sign up to request clarification or add additional context in comments.

6 Comments

But would it guarantee the uniqueness between multiple runs of the program?
According to the docs, it will guarantee that (1)The file denoted by the returned abstract pathname did not exist before this method was invoked, and (2) Neither this method nor any of its variants will return the same abstract pathname again in the current invocation of the virtual machine. So, if you are creating files in the same directory - and not deleting them - yes, they would be unique.
does it delete the file after close ? or have you to delete it when you finish with it ?
You have to delete the file. File testFile = File.createTempFile("MyApp", ".tmp", outputDirectory); testFile.delete();
@Lucke deleteOnExit()
|
32

I'd use Apache Commons Lang library (http://commons.apache.org/lang).

There is a class org.apache.commons.lang.RandomStringUtils that can be used to generate random strings of given length. Very handy not only for filename generation!

Here is the example:

String ext = "dat";
File dir = new File("/home/pregzt");
String name = String.format("%s.%s", RandomStringUtils.randomAlphanumeric(8), ext);
File file = new File(dir, name);

4 Comments

@marcolopes: But the chances for equal names for two files are extremely small. In case we have 62 different characters (I don't know how many RandomStringUtils use; 62 is my guess for case-sensitive) it's 62^n where n is your file name length. For the above example with a length of 8 the chance would be 2.183401056×10¹⁴.
@Kris still though, with a few lines of code you could have a 100% guarantee of uniqueness (or by just using one of the existing methods).
This is not an idiomatic way. You better avoid it. Use temporary files, as suggested.
Include another library alltogether in project just to generate a random filename?? Not a viable solution I say.
13

I use the timestamp

i.e

new File( simpleDateFormat.format( new Date() ) );

And have the simpleDateFormat initialized to something like as:

new SimpleDateFormat("File-ddMMyy-hhmmss.SSS.txt");

EDIT

What about

new File(String.format("%s.%s", sdf.format( new Date() ),
                                random.nextInt(9)));

Unless the number of files created in the same second is too high.

If that's the case and the name doesn't matters

 new File( "file."+count++ );

:P

3 Comments

Yes, but what if two files are created in the same second, or millisecond.
millisecond isn't likely, and you could put a timer on it to stop files being created in the same second ...
@JeffBloom I have encountered a problem similar to what you're asking. I am creating a file and the file name has System.currentTimeMillis() in it. Suppose i copy the file and paste another file with same System.currentTimeMillis(), it won't read my next file. How can i not allow user to copy and paste files which has same System.currentTimeMillis(). Any help would be greatly appreciated
10

This works for me:

String generateUniqueFileName() {
    String filename = "";
    long millis = System.currentTimeMillis();
    String datetime = new Date().toGMTString();
    datetime = datetime.replace(" ", "");
    datetime = datetime.replace(":", "");
    String rndchars = RandomStringUtils.randomAlphanumeric(16);
    filename = rndchars + "_" + datetime + "_" + millis;
    return filename;
}

// USE:

String newFile;
do{
newFile=generateUniqueFileName() + "." + FileExt;
}
while(new File(basePath+newFile).exists());

Output filenames should look like :

2OoBwH8OwYGKW2QE_4Sep2013061732GMT_1378275452253.Ext

2 Comments

This does not guarantee a unique file name. However, you could expand this answer by checking if the file exists, and if so generate another random string.
Thanks @CalebAdams :) This probably can happen in case multi-threads. updated.
8

Look at the File javadoc, the method createNewFile will create the file only if it doesn't exist, and will return a boolean to say if the file was created.

You may also use the exists() method:

int i = 0;
String filename = Integer.toString(i);
File f = new File(filename);
while (f.exists()) {
    i++;
    filename = Integer.toString(i);
    f = new File(filename);
}
f.createNewFile();
System.out.println("File in use: " + f);

1 Comment

I don't know if I'm over thinking it. What happens if f is created by another process after the while loop and before the f.createNewFile() call?
3

If you have access to a database, you can create and use a sequence in the file name.

select mySequence.nextval from dual;

It will be guaranteed to be unique and shouldn't get too large (unless you are pumping out a ton of files).

1 Comment

Why on earth is this downvoted? While it's clearly not going to be the most elegant solution, it should at least statisfy the OP's requirements. I think it's a completely valid approach to consider, espescially if OP plans to somehow incorporate this information with a database.
3
    //Generating Unique File Name
    public String getFileName() {
        String timeStamp = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss").format(new Date());
        return "PNG_" + timeStamp + "_.png";
    }

3 Comments

The method above does not guarantee that two quick calls (or two different threads at same time) return unique results.
@usr-local-ΕΨΗΕΛΩΝ you can also append user id so that that file name would be unique and abt thread we can use rxJava for that
Sorry I must strongly disagree. Two threads from same user will clash. And your API must require implementors to gather user id. Java is famous for being portable, what if your voice runs on a userless IoT device? The right way is to perform a for cycle appending an increasing suffix until no file with that suffix is found, and to immediately create that file. This is the same File.createTempFile does under the hood
3

I use current milliseconds with random numbers

i.e

Random random=new Random();
String ext = ".jpeg";
File dir = new File("/home/pregzt");
String name = String.format("%s%s",System.currentTimeMillis(),random.nextInt(100000)+ext);
File file = new File(dir, name);

1 Comment

It's dangerous if you could have several threads generating files at the same time
2

Combining other answers, why not use the ms timestamp with a random value appended; repeat until no conflict, which in practice will be almost never.

For example: File-ccyymmdd-hhmmss-mmm-rrrrrr.txt

Comments

2

Problem is synchronization. Separate out regions of conflict.

Name the file as : (server-name)_(thread/process-name)_(millisecond/timestamp).(extension)
example : aws1_t1_1447402821007.png

Comments

1

Why not just use something based on a timestamp..?

4 Comments

What if two files are created in the same millisecond?
Retry for the failure, the new timestamp will then be different
@Jeff. Just detect the conflict and try again until there is no conflict; in practice this should be very rare.
If you're going to detect the conflict anyway, just generate a random filename without worrying about the time - see my answer, for example. It's still going to be pretty rare that you generate the same filename with (say) 8 characters in :)
0

How about generate based on time stamp rounded to the nearest millisecond, or whatever accuracy you need... then use a lock to synchronize access to the function.

If you store the last generated file name, you can append sequential letters or further digits to it as needed to make it unique.

Or if you'd rather do it without locks, use a time step plus a thread ID, and make sure that the function takes longer than a millisecond, or waits so that it does.

1 Comment

Using lock synchronization for things like that is almost always a horrible idea -- mutexes are good for protecting program's internal memory, not any outside resources (e.g. database, file system).
0

It looks like you've got a handful of solutions for creating a unique filename, so I'll leave that alone. I would test the filename this way:

    String filePath;
    boolean fileNotFound = true;
    while (fileNotFound) {
        String testPath = generateFilename();

        try {
            RandomAccessFile f = new RandomAccessFile(
                new File(testPath), "r");
        } catch (Exception e) {
            // exception thrown by RandomAccessFile if 
            // testPath doesn't exist (ie: it can't be read)

            filePath = testPath;
            fileNotFound = false;
        }
    }
    //now create your file with filePath

Comments

0

This also works

String logFileName = new SimpleDateFormat("yyyyMMddHHmm'.txt'").format(new Date());

logFileName = "loggerFile_" + logFileName;

Comments

0

I understand that I am too late to reply on this question. But I think I should put this as it seems something different from other solution.

We can concatenate threadname and current timeStamp as file name. But with this there is one issue like some thread name contains special character like "\" which can create problem in creating file name. So we can remove special charater from thread name and then concatenate thread name and time stamp

fileName = threadName(after removing special charater) + currentTimeStamp

Comments

0

Why not use synchronized to process multi thread. here is my solution,It's can generate a short file name , and it's unique.

private static synchronized String generateFileName(){
    String name = make(index);
    index ++;
    return name;
}
private static String make(int index) {
    if(index == 0) return "";
    return String.valueOf(chars[index % chars.length]) + make(index / chars.length);
}
private static int index = 1;
private static char[] chars = {'a','b','c','d','e','f','g',
        'h','i','j','k','l','m','n',
        'o','p','q','r','s','t',
        'u','v','w','x','y','z'};

blew is main function for test , It's work.

public static void main(String[] args) {
    List<String> names = new ArrayList<>();
    List<Thread> threads = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    String name = generateFileName();
                    names.add(name);
                }
            }
        });
        thread.run();
        threads.add(thread);
    }

    for (int i = 0; i < 10; i++) {
        try {
            threads.get(i).join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    System.out.println(names);
    System.out.println(names.size());

}

Comments

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.