在Java中生成唯一和短文件名的最佳方法是什么

时间:2009-05-05 16:13:57

标签: java file

我不一定要使用UUID,因为它们相当长。

该文件只需在其目录中是唯一的。

我想到的一个想法是使用File.createTempFile(String prefix, String suffix),但这似乎是错误的,因为该文件不是临时的。

需要处理以相同毫秒创建的两个文件的情况。

16 个答案:

答案 0 :(得分:83)

好吧,你可以使用3参数版本:File.createTempFile(String prefix, String suffix, File directory),它可以让你把它放在你想要的地方。除非你告诉它,否则Java不会以不同于任何其他文件的方式对待它。唯一的缺点是文件名保证长度至少为8个字符(前缀最少3个字符,加上函数生成的5个或更多字符)。

如果这对你来说太长了,我想你总是可以从文件名“a”开始,然后循环“b”,“c”等,直到找到一个尚不存在的文件。

答案 1 :(得分:27)

我使用Apache Commons Lang库( http://commons.apache.org/lang)。

有一个类org.apache.commons.lang.RandomStringUtils可用于生成给定长度的随机字符串。 非常方便,不仅仅是文件名生成!

以下是示例:

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

答案 2 :(得分:12)

我使用时间戳

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

将simpleDateFormat初始化为类似:

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

修改

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

除非在同一秒内创建的文件数太多。

如果是这种情况并且名称不重要

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

:P

答案 3 :(得分:10)

这对我有用:

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

输出文件名应如下所示:

2OoBwH8OwYGKW2QE_4Sep2013061732GMT_1378275452253.Ext

答案 4 :(得分:6)

查看File javadoc,createNewFile方法只有在文件不存在时才会创建文件,并返回一个布尔值来说明文件是否已创建。

您也可以使用exists()方法:

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 :(得分:5)

如果您有权访问数据库,则可以在文件名中创建和使用序列。

select mySequence.nextval from dual;

它将保证是唯一的,不应该太大(除非你抽出大量的文件)。

答案 6 :(得分:2)

为什么不使用基于时间戳的东西..?

答案 7 :(得分:2)

结合其他答案,为什么不使用带有随机值的ms时间戳;重复,直到没有冲突,实际上几乎不会发生冲突。

例如:File-ccyymmdd -hhmmss-mmm-rrrrrr.txt

答案 8 :(得分:1)

 {
  "name": "TOPICS",
  "children": [
    {
      "name": "Topic A",
      "children": [
        {
          "name": "Sub A1"
        },
        {
          "name": "Sub A2",
          "children": [
            {
              "name": "Topic B",
              "children": [
                {
                  "name": "Sub B1"
                },
                {
                  "name": "Sub B2"
                },
                {
                  "name": "Sub B3"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

root = d3.hierarchy(root);   
root.sum(d => d.size);

答案 9 :(得分:0)

如何基于四舍五入到最接近的毫秒的时间戳或者您需要的任何精度生成...然后使用锁来同步对函数的访问。

如果存储最后生成的文件名,则可以根据需要在其中附加连续字母或更多数字,以使其唯一。

或者如果您不想使用锁定,请使用时间步长加上一个线程ID,并确保该函数花费的时间超过一毫秒,或等待它完成。

答案 10 :(得分:0)

看起来你已经有了一些用于创建唯一文件名的解决方案,所以我将一个人留下。我会用这种方式测试文件名:

    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

答案 11 :(得分:0)

这也有效

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

logFileName = "loggerFile_" + logFileName;

答案 12 :(得分:0)

据我所知,我对这个问题的答复为时已晚。但我认为我应该把它看成与其他解决方案不同的东西。

我们可以将threadname和当前timeStamp连接为文件名。但是有一个问题就像一些线程名称包含像“\”这样的特殊字符,这可能会在创建文件名时产生问题。所以我们可以从线程名称中删除特殊字符,然后连接线程名称和时间戳

fileName = threadName(after removing special charater) + currentTimeStamp

答案 13 :(得分:0)

为什么不使用synchronized来处理多线程。 这是我的解决方案,它可以生成一个短文件名,而且它是唯一的。

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'};

自爆是测试的主要功能,这是工作。

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

}

答案 14 :(得分:0)

问题是同步。分开冲突地区。

将文件命名为:(server-name)_(thread/process-name)_(millisecond/timestamp).(extension)
示例:aws1_t1_1447402821007.png

答案 15 :(得分:0)

我使用随机数表示的当前毫秒数

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