Java 如何对列表进行排序<;文件>;首先列出目录并按目录对文件进行分组?

Java 如何对列表进行排序<;文件>;首先列出目录并按目录对文件进行分组?,java,algorithm,sorting,apache-commons,comparator,Java,Algorithm,Sorting,Apache Commons,Comparator,为了获取指定目录中包含的所有文件,并根据一些扩展名,我使用了库中的class方法,如下面的代码示例所示 ArrayList<String> wildcards = new ArrayList<>(); wildcards.add("*.cpp"); wildcards.add("*.h"); wildcards.add("*.txt"); File dir = new File("/path/to/dir"); Collection<File> found

为了获取指定目录中包含的所有文件,并根据一些扩展名,我使用了库中的class方法,如下面的代码示例所示

ArrayList<String> wildcards = new ArrayList<>();
wildcards.add("*.cpp");
wildcards.add("*.h");
wildcards.add("*.txt");

File dir = new File("/path/to/dir");
Collection<File> found = FileUtils.listFiles(
        dir,
        new WildcardFileFilter(wildcards, IOCase.SENSITIVE),
        DirectoryFileFilter.DIRECTORY);

List<File> files = new ArrayList<>(found);

只是打字的问题;下面我不采用规范路径(Windows不区分大小写),但要点很清楚

因此用于排序的
比较器

public class FileComparator extends Comparator<File> {

    @Override
    public int compareTo(File lhs, File rhs) {
        if (lhs == null && rhs == null) {
            return 0;
        } else if (lhs == null || rhs == null) {
            return lhs == null ? -1 : 1;
        }
        int cmp = compareTo(lhs.getParentFile(), rhs.getParentFile());
        if (cmp == 0) {
            if (lhs.isDirectory() != rhs.isDirectory()) {
                return lhs.isDirectory() ? -1 : 1;
            }
            cmp = lhs.getName().compareTo(rhs.getName());
        }
        return cmp;
    }

    @Override
    public boolean equals(Object comparator) {
        return comparator != null && comparator.getClass().equals(getClass());
    }
}
公共类FileComparator扩展了Comparator{
@凌驾
公共整数比较(文件lhs、文件rhs){
if(lhs==null&&rhs==null){
返回0;
}else if(lhs==null | | rhs==null){
返回lhs==null?-1:1;
}
int cmp=compareTo(lhs.getParentFile(),rhs.getParentFile());
如果(cmp==0){
if(lhs.isDirectory()!=rhs.isDirectory()){
返回lhs.isDirectory()?-1:1;
}
cmp=lhs.getName().compareTo(rhs.getName());
}
返回cmp;
}
@凌驾
公共布尔等于(对象比较器){
返回比较器!=null&&comparator.getClass().equals(getClass());
}
}

像往常一样,
equals
只比较比较器,而不是文件。

您可以使用Java8的
流来解决您的问题。像这样的方法应该会奏效:

//untested
Map<Path, List<Path>> dirToFileMap = files.stream()
            .map(f -> Paths.get(f.getAbsolutePath()))
            .collect(Collectors.groupingBy(Path::getParent));
//未经测试
Map dirToFileMap=files.stream()
.map(f->path.get(f.getAbsolutePath())
.collect(Collectors.groupingBy(Path::getParent));

有了这张地图,你就能实现你所需要的。例如,首先迭代
键集。

整个下午我都在为此挠头,下面是对我有效的方法:

files.sort((p1,p2)->pathToStr(p1).compareToIgnoreCase(pathToStr(p2));
files.forEach(System.out::println)//现在就要点菜了!
//我为实现这一目标而编写的方法
公共静态字符串pathToStr(文件路径){
布尔值isDir=path.isDirectory();
字符串str=path.getAbsolutePath().replace(“\\”,“/”).replace(“/”,“/\0”);
if(!isDir){
int idx=str.lastIndexOf(“/\0”);
str=str.substring(0,idx)+str.substring(idx,str.length())。替换(“/\0”,“/”);
}
返回str;
}
因此,基本上,
pathToStr()
所做的是对文件路径进行字符串表示,但有一点扭曲:路径中的所有文件夹名称都将有一个空的
\0
字符前缀。这样,股票字符串排序将把所有子文件夹推到每个文件夹的顶部。只要您没有任何文件名以空字符开头,它就可以正常工作,我认为这甚至不可能,因为旧C处理字符串的能力很好

作为补充说明,如果您想以更为类似UNIX的方式订购东西,您可以将<<代码> CaseRealEngaseCase<代码>改为<代码> CuasReto ,以便考虑不同的外壳。 这个问题可能有点老了(我写这篇文章的时候已经5岁了),但我找不到任何不涉及使用库或混合几个比较器的答案,所以一旦我弄明白了,我决定回到这里,加上我的2美分。享受你节省下来的下午

编辑:由于问题没有使用NIO路径,我不得不仅使用
文件将代码更改为另一个版本
;但如果您像我一样使用NIO路径,下面是我使用的代码:

List items=Files.walk(rootFolder.collect(Collectors.toList());
排序((p1,p2)->pathToStr(p1).compareToIgnoreCase(pathToStr(p2));
items.forEach(System.out::println)//现在就要点菜了!
公共静态字符串pathToStr(路径路径){
布尔isDir=Files.isDirectory(路径,LinkOption.NOFOLLOW\u链接);
String str=path.toabsolutionPath().toString().replace(“\\”,“/”).replace(“/”,“/\0”);
if(!isDir){
int idx=str.lastIndexOf(“/\0”);
str=str.substring(0,idx)+str.substring(idx,str.length())。替换(“/\0”,“/”);
}
返回str;
}

好了,不管你是否使用NIO,这个答案已经涵盖了你。

按完整路径名对文件进行排序应该可以了,不是吗?@ammoQ:不幸的是没有,因为例如
/path/to/dir/README.txt
如果我按完整路径名对它们进行排序,那么将小于
/path/to/dir/second/utils.h
,这取决于您是否将
README.txt
视为
dir
节点的叶子树,该节点位于
第二个
节点之前。如果您想先拥有目录,它与深度优先完全不同。您可以在apache公共io库中使用以下比较器之一:。尝试使用DefaultFileComparator或DirectoryFileComparator或PathFileComparator或组合comparator中的少数几个-因此在比较例程中,按路径(不带文件名)排序,如果路径相等,则按文件名排序。这个问题已经存在5年了。我认为NIO解决方案是更好的方法在2020。
//untested
Map<Path, List<Path>> dirToFileMap = files.stream()
            .map(f -> Paths.get(f.getAbsolutePath()))
            .collect(Collectors.groupingBy(Path::getParent));