Java 8 - 按大小改进大量文件的排序时间

时间:2018-02-05 00:03:45

标签: java sorting comparator

我查了sorting files in directory by size using java array list&& How to sort an ArrayList by its elements size in Java?

我的问题是,实施比较器的最佳方法是什么,以便排序更快?我被告知, 100k文件的排序应该在几秒钟内完成,而不是几分钟,因为文件大小很长。 有没有更好的方法来实现比较器?

我的比较者是:

public static List<File> sortFilesBySize(List<File> xmlFileList) {
     xmlFileList.sort(Comparator.comparing(File::length).reversed());
     return xmlFileList;
}

,其中

private static List<File> xmlFileList = new ArrayList<File>();

xmlFileList填充为:

pathList = pathList.subList(0,filterCount);
for (Path filePath : pathList)
    xmlFileList.add(filePath.toFile());

filterCount是我按照要排序的文件数进行过滤的方式

并将sortFilesBySize调用为:

long startSortMillis = System.currentTimeMillis();
sortFilesBySize(xmlFileList);
long timeInMillis = System.currentTimeMillis() - startSortMillis;

通过改变排序为5k,10k 20k等的文件数量,我得到了

  1. 5k ----&gt; 1329 ms
  2. 10k ---&gt; 2808 ms
  3. 20k ---&gt; 29790 ms
  4. 40k ---&gt; 428408 ms
  5. 80k ---&gt; 838658 ms
  6. 100k - &gt; 1159034 ms
  7. 可以观察到,20k后排序需要几分钟。有什么建议我可以降低排序时间吗?

    我也抬头https://docs.oracle.com/javase/8/docs/api/java/io/File.html看看我是否可以改进目前的实施情况,但似乎什么都没有跳出来。

4 个答案:

答案 0 :(得分:2)

确实是由File.length()上的系统调用引起的。它们的数量随着文件数量的增加而增加。按照建议缓存它。你会发现排序时间几乎消失了。

答案 1 :(得分:1)

尝试缓存长度:

public static List<FileWithCachedLength> sortFilesBySize(List<FileWithCachedLength> xmlFileList) {
    xmlFileList.sort(Comparator.comparing(FileWithCachedLength::length).reversed());
    return xmlFileList;
}

其中:

public class FileWithCachedLength {
    private final File file;
    private final int length;
    // getters omitted
    public FileWithCachedLength( File f ) {
        file = f;
        length = f.length();
    }
}

答案 2 :(得分:0)

正如其他人所说,这是由于File.length()方法的成本。

如果你有这样的方法:

public static <T, R> Function<T, R> memoized(Function<? super T, ? extends R> f) {
    Objects.requireNonNull(f);
    Map<T, R> map = new HashMap<>();
    return t -> map.computeIfAbsent(t, f);
}

您可以像这样使用它:

public static List<File> sortFilesBySize(List<File> xmlFileList) {
    xmlFileList.sort(Comparator.comparing(memoized(File::length)).reversed());
    return xmlFileList;
}

只会为每个文件调用一次File.length()费用。

答案 3 :(得分:0)

感谢所有的答案,他们非常有帮助。我选择了MiguelKVidal建议的实现。

我从审核Java Pairs开始 - 来自http://www.baeldung.com/java-pairs

实施后,我的排序时间很好而且很低。但走目录路径的时间更长:

  1. 5k ----&gt;排序(16毫秒)-----&gt; WalkDirectoryPath(102秒)
  2. 10k ---&gt;排序(31毫秒)-------&gt; WalkDirectoryPath(94秒)
  3. 20k ----&gt;排序(68毫秒)-------&gt; WalkDirectoryPath(177秒)
  4. 40k ----&gt;排序(131毫秒)-----&gt; WalkDirectoryPath(328秒)
  5. 80k ----&gt;排序(158毫秒)-----&gt; WalkDirectoryPath(1219秒)
  6. 100k ---&gt;排序(322毫秒)----&gt; WalkDirectoryPath(479秒)