40

I write application in Java using SWT. I would like to create unique file name. But I do not want create it on hard drive. Additional functionality: I want to create unique file name in specify folder.

public String getUniqueFileName(String directory, String extension) {
        //create unique file name   
}
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • If you don't create the file, then what do you mean exactly by "unique"? Do you mean, "different from all the other file names in that directory"? – lindelof Aug 18 '09 at 13:08
  • I would like to create unique file name: "different from all the other file names in that directory" - exactly. – Michał Ziober Aug 18 '09 at 13:18
  • 4
    @mykhaylo: Realize that if you do not immediately create a file using the unique file name you are obtaining there is the possibility that another file with that name could pop into existence. Even some of the answers provided do not account for this possibility. – Grant Wagner Aug 18 '09 at 16:16

8 Answers8

23

From your question I assume you've seen that File.createTempFile() always creates a file rather than just allowing you to generate the name.

But why not just call the method and then delete the temporary file created? createTempFile() does all the work in finding a unique file name in the specified directory and since you created the file you can sure you'll be to delete it too.

File f = File.createTempFile("prefix",null,myDir);
String filename = f.getName();
f.delete();
lbalazscs
  • 17,474
  • 7
  • 42
  • 50
David Webb
  • 190,537
  • 57
  • 313
  • 299
  • 21
    @Dave: After `f.delete()` the file name is no longer guaranteed to be unique. Right after you remove the one created by `createTempFile()` another file with the same name could appear on the file system. – Grant Wagner Aug 18 '09 at 16:18
  • @Grant Wagner: Exactly. That is why operation needs to be atomic. If you just want to generate a random name than just concatenate timestamp with some random numbers – polvoazul Aug 18 '16 at 19:28
  • 1
    @polvoazul: Unfortunately there is no way to do what @michał-ziober is asking and guarantee that the filename is still unused in that directory. Not with GUID/UUID, not with timestamps and random numbers. It's just not possible. @dave-webb's answer is the closest you're going to get to a standard (by calling the built-in `File.createTempFile`). Deleting the file after is only done to satisfy the original questions constraints. – onlynone Dec 13 '16 at 15:26
7

Use a timestamp in the filename?

Of course this may not work if you have very high concurrency.

For example:

public String getUniqueFileName(String directory, String extension) {
    return new File(directory, new StringBuilder().append("prefix")
        .append(date.getTime()).append(UUID.randomUUID())
        .append(".").append(extension).toString()).getAbsolutePath();
}

AS John Oxley's answer suggests. UUID may be a solution as you can use 4 different schemes to create them. Though there is still a small chance of a collision. If you combine a timestamp with a random UUID the chances of any collision becomes vanishingly small.

Community
  • 1
  • 1
Rich Seller
  • 83,208
  • 23
  • 172
  • 177
4

Using the Path API available from Java 7 you can generate a temporary Path file with a uniquely generated name.

The Files utility class provides Files.createTempFile, which works in a similar manner as File.createTempFile, except it produces a Path object

So calling the method

Path baseDir = ...
Files.createTempFile(baseDir, "status-log-", ".log");
//                 //dir path, prefix      , suffix

Will produce something similar to

C:\...\status-log-4746781128777680321.log

If you want to open the file and delete it after you're done with it, you can use DELETE_ON_CLOSE, taken from the docs:

As with the File.createTempFile methods, this method is only part of a temporary-file facility. Where used as a work files, the resulting file may be opened using the DELETE_ON_CLOSE option so that the file is deleted when the appropriate close method is invoked. Alternatively, a shutdown-hook, or the File.deleteOnExit mechanism may be used to delete the file automatically.

svarog
  • 9,477
  • 4
  • 61
  • 77
3

You could try using a GUID for the file name.

JonnyD
  • 591
  • 1
  • 6
  • 12
3

Another Version,

Simplified the other answers, Use GUID. imho no need to add salt to UUID. This is what i'm using:

public static String getUniqueFileName(String directory, String extension) {
    String fileName = MessageFormat.format("{0}.{1}", UUID.randomUUID(), extension.trim());
    return Paths.get(directory, fileName).toString();
}
  • note that the file is not being created, this function just returns a unique filename as string

usage:

String uniqueFileName = getUniqueFileName("/tmp", "pdf");
System.out.println(uniqueFileName);

output

/tmp/f34a960a-6001-44d6-9aa7-93ec6647a64a.pdf
Community
  • 1
  • 1
Jossef Harush Kadouri
  • 32,361
  • 10
  • 130
  • 129
2

you can create an actual unique directory (sub-directory) and then any file inside it should be unique, for example "myFile." + extension

  public static String getUniqueFileName(String directory, String extension) {
     try
     {
        // create actual unique subdirectory in the given directory
        //
        File myUniqueDir = File.createTempFile("udir", null,directory);
        String filename = myUniqueDir.getName();
        myUniqueDir.delete (); // don't want the file but a directory
        myUniqueDir.mkdirs ();
     }
     //todo: catch ....

     // for example:
     return directory + "/" + myUniqueDir + "/myFile." + extension;
  }

this procedure should work in normal scenarios even with concurrency. Unless we start thinking in sniffer processes that want to occupy our new directory or similar things.

elxala
  • 291
  • 3
  • 5
1

You can create a file with any name (time, GUID, etc) and then test it to see if it already exists. If it does, then try another name to see if it's unique.

File f = new File(guid);
if (f.exists()) {
  //try another guid
}else{
  //you're good to go
}
Nick
  • 1,340
  • 1
  • 15
  • 23