Java 如何对列表进行排序<;文件>;首先列出目录并按目录对文件进行分组?
为了获取指定目录中包含的所有文件,并根据一些扩展名,我使用了库中的class方法,如下面的代码示例所示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
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));