What is the best way to generate a unique and short file name in Java

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.

138114 次浏览

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

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

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.

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);

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.

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

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);

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).

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

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

This also works

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


logFileName = "loggerFile_" + logFileName;

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

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());


}
    //Generating Unique File Name
public String getFileName() {
String timeStamp = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss").format(new Date());
return "PNG_" + timeStamp + "_.png";
}

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

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);