[java] 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.

This question is related to java file

The answer is


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

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


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


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


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

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


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 also works

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

logFileName = "loggerFile_" + logFileName;

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

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

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.


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

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

}

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


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