web-dev-qa-db-fra.com

Quel est le meilleur moyen de générer un nom de fichier unique et court en Java

Je ne veux pas nécessairement utiliser les UUID car ils sont assez longs.

Le fichier doit simplement être unique dans son répertoire.

Une idée qui me vient à l’esprit est d’utiliser File.createTempFile(String prefix, String suffix), mais cela semble faux car le fichier n’est pas temporaire.

Le cas de deux fichiers créés dans la même milliseconde doit être traité.

65
Jeff Bloom

Eh bien, vous pouvez utiliser la version à 3 arguments: File.createTempFile(String prefix, String suffix, File directory) qui vous permettra de la placer où vous le souhaitez. À moins que vous ne le lui disiez, Java ne le traitera pas différemment des autres fichiers. Le seul inconvénient est que le nom du fichier est garanti avec au moins 8 caractères (minimum de 3 caractères pour le préfixe, plus 5 caractères ou plus générés par la fonction).

Si cela vous prend trop de temps, je suppose que vous pouvez toujours simplement commencer par le nom de fichier "a" et parcourir en boucle "b", "c", etc. jusqu'à ce que vous en trouviez un qui n'existe pas déjà.

79
Pesto

J'utiliserais la bibliothèque Apache Commons Lang (  http://commons.Apache.org/lang).

Il existe une classe org.Apache.commons.lang.RandomStringUtils qui peut être utilisée pour générer des chaînes aléatoires de longueur donnée. Très pratique non seulement pour la génération de nom de fichier!

Voici l'exemple:

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

J'utilise l'horodatage

c'est à dire

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

Et avez le simpleDateFormat initialisé à quelque chose comme:

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

MODIFIER

Qu'en est-il de

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

Sauf si le nombre de fichiers créés dans la même seconde est trop élevé. 

Si c'est le cas et que le nom ne compte pas

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

: P

11
OscarRyz

Cela fonctionne pour moi:

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

Les noms de fichiers de sortie doivent ressembler à:

2OoBwH8OwYGKW2QE_4Sep2013061732GMT_1378275452253.Ext
10

Si vous avez accès à une base de données, vous pouvez créer et utiliser une séquence dans le nom du fichier. 

select mySequence.nextval from dual;

Il sera garanti d'être unique et ne devrait pas devenir trop volumineux (sauf si vous extrayez une tonne de fichiers).

5
Shane

Regardez dans le fichier javadoc , la méthode createNewFile créera le fichier uniquement s'il n'existe pas et renverra un booléen indiquant si le fichier a été créé.

Vous pouvez également utiliser la méthode exist ():

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

Pourquoi ne pas simplement utiliser quelque chose basé sur un horodatage ..?

2
Galwegian

En combinant d'autres réponses, pourquoi ne pas utiliser l'horodatage ms avec une valeur aléatoire ajoutée; répétez jusqu'à ce qu'il n'y ait pas de conflit, ce qui en pratique ne sera presque jamais.

Par exemple: fichier-ccyymmdd-hhmmss-mmm-rrrrrr.txt

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

Je comprends que je suis trop tard pour répondre à cette question. Mais je pense que je devrais dire ceci car il semble que quelque chose de différent d'une autre solution.

Nous pouvons concaténer threadname et timeStamp en tant que nom de fichier. Mais avec cela, il y a un problème tel qu'un nom de fil contenant un caractère spécial comme "\" qui peut créer un problème lors de la création d'un nom de fichier. Nous pouvons donc supprimer les caractères spéciaux du nom du fil, puis concaténer le nom du fil et l’horodatage.

fileName = threadName(after removing special charater) + currentTimeStamp
0
Roshan

Cela fonctionne aussi

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

logFileName = "loggerFile_" + logFileName;
0
T.Akshay

Le problème est la synchronisation. Séparez les régions de conflit.

Nommez le fichier comme suit: (server-name)_(thread/process-name)_(millisecond/timestamp).(extension)
exemple: aws1_t1_1447402821007.png

0
smit thakkar

On dirait que vous avez une poignée de solutions pour créer un nom de fichier unique, je vais donc le laisser tranquille. Je testerais le nom de fichier de cette façon:

    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
0
Peter Anthony

Que diriez-vous de générer en fonction d'un horodatage arrondi à la milliseconde près, ou de la précision dont vous avez besoin ... utilisez ensuite un verrou pour synchroniser l'accès à la fonction.

Si vous stockez le dernier nom de fichier généré, vous pouvez lui ajouter des lettres séquentielles ou des chiffres supplémentaires si nécessaire pour le rendre unique. 

Ou, si vous préférez le faire sans verrou, utilisez un pas de temps et un ID de thread et assurez-vous que la fonction dure plus d'une milliseconde ou attend.

0
justinhj

Pourquoi ne pas utiliser synchronisé pour traiter plusieurs threads . Voici ma solution, elle peut générer un nom de fichier court, et il est 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 est la fonction principale du test, c’est le travail.

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

}
0
Ignore