6

我有一个文件夹,其中包含以时间戳命名的文件。

当我尝试浏览每个文件时,它会按字母顺序对它们进行排序并给我这个顺序:

/home/user/buffereddata/1
/home/user/buffereddata/100
/home/user/buffereddata/1000
/home/user/buffereddata/200
/home/user/buffereddata/2000
/home/user/buffereddata/300

但我希望它们像这样排序:

/home/user/buffereddata/1
/home/user/buffereddata/100
/home/user/buffereddata/200
/home/user/buffereddata/300
/home/user/buffereddata/1000
/home/user/buffereddata/2000

这是我的代码:

File file = new File(System.getProperty("user.home") + "/buffereddata");

if(file.exists()) {
  File[] fileArray = file.listFiles();
  Arrays.sort(fileArray);
  for(File f : fileArray) {
    System.out.println(f);
  }
}

是否有一些(最好是简单的)方法以我想要循环的方式循环文件?

4

4 回答 4

14
Arrays.sort(fileArray, new Comparator<File>() {
    public int compare(File f1, File f2) {
        try {
            int i1 = Integer.parseInt(f1.getName());
            int i2 = Integer.parseInt(f2.getName());
            return i1 - i2;
        } catch(NumberFormatException e) {
            throw new AssertionError(e);
        }
    }
});
于 2013-06-27T09:51:53.183 回答
3

你需要一个自定义比较器

    Arrays.sort(fileArray, new Comparator<File>() {
        public int compare(File f1, File f2) {
            int n1 = Integer.parseInt(f1.getName());
            int n2 = Integer.parseInt(f1.getName());
            return Integer.compare(n1, n2);
        }});
于 2013-06-27T09:53:42.170 回答
3

虽然其他答案在您的特定情况下是正确的(给定目录中的所有文件名都是数字),但这里有一个可以比较混合数字/非数字文件名的解决方案,例如version-1.10.3.txt以直观的方式,类似于 Windows 的方式资源管理器这样做:

在此处输入图像描述

这个想法(我在这里写过博客这个想法的灵感来自这里的答案。)是将文件名拆分为数字/非数字段,然后以数字方式比较两个文件名中的每个单独段(如果两者都是数字),或其他字母数字:

public final class FilenameComparator implements Comparator<String> {
    private static final Pattern NUMBERS = 
        Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
    @Override public final int compare(String o1, String o2) {
        // Optional "NULLS LAST" semantics:
        if (o1 == null || o2 == null)
            return o1 == null ? o2 == null ? 0 : -1 : 1;

        // Splitting both input strings by the above patterns
        String[] split1 = NUMBERS.split(o1);
        String[] split2 = NUMBERS.split(o2);
        for (int i = 0; i < Math.min(split1.length, split2.length); i++) {
            char c1 = split1[i].charAt(0);
            char c2 = split2[i].charAt(0);
            int cmp = 0;

            // If both segments start with a digit, sort them numerically using 
            // BigInteger to stay safe
            if (c1 >= '0' && c1 <= '9' && c2 >= 0 && c2 <= '9')
                cmp = new BigInteger(split1[i]).compareTo(new BigInteger(split2[i]));

            // If we haven't sorted numerically before, or if numeric sorting yielded 
            // equality (e.g 007 and 7) then sort lexicographically
            if (cmp == 0)
                cmp = split1[i].compareTo(split2[i]);

            // Abort once some prefix has unequal ordering
            if (cmp != 0)
                return cmp;
        }

        // If we reach this, then both strings have equally ordered prefixes, but 
        // maybe one string is longer than the other (i.e. has more segments)
        return split1.length - split2.length;
    }
}

然后,您可以像这样使用比较器:

Arrays.sort(fileArray, Comparators.comparing(File::getName, new FilenameComparator()));
于 2018-02-23T11:30:40.080 回答
-1

基于这个答案

您可以使用比较功能定义自己的比较器:

public class FileSizeComparator implements Comparator<File> {
    public int compare( File a, File b ) {
        String aName = a.getName();
        String bName = b.getName();
        // make both strings equal size by padding 0s to the smaller one
        // then compare the strings
        return aName.compareTo(bName); // dictionary order!
    }
}

compareTo是一种String对您有益的类方法。

"0100".compareTo("1000"); // < 0
"0100".compareTo("0200"); // < 0
"0200".compareTo("1000"); // < 0

因此,如果您有 100、200、1000,您将获得 100、200、1000 而不是 100、1000、200!

应该工作,未经测试!

于 2013-06-27T09:52:53.333 回答