为了获取指定目录中包含的所有文件并根据某些扩展名,我使用listFiles
库中FileUtils
类Apache Commons IO的方法,如以下代码示例。
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);
结果Collection<File>
中的项目顺序在不同的操作系统中有所不同,因此我会根据以下规则对它们进行排序(即包装列表files
)。
示例:
/path/to/dir/first/subpath/main.cpp
/path/to/dir/first/subpath/utils.cpp
/path/to/dir/first/subpath/utils.h
/path/to/dir/first/main.cpp
/path/to/dir/first/utils.cpp
/path/to/dir/first/utils.h
/path/to/dir/second/main.cpp
/path/to/dir/second/utils.cpp
/path/to/dir/second/utils.h
/path/to/dir/README.txt
答案 0 :(得分:3)
您可以使用Java 8的stream
来解决您的问题。这样的事情应该有效:
//untested
Map<Path, List<Path>> dirToFileMap = files.stream()
.map(f -> Paths.get(f.getAbsolutePath()))
.collect(Collectors.groupingBy(Path::getParent));
使用该地图,您可以实现所需。例如,首先迭代keySet
。
答案 1 :(得分:1)
只是打字的问题;下面我不采用规范路径(Windows不区分大小写),但要点很清楚。
所以Comparator
用于排序:
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());
}
}
与equals
一样,只比较比较器,而不是文件。
答案 2 :(得分:1)
整个下午都为此挠头之后,这是对我有用的方法:
files.sort((p1, p2) -> pathToStr(p1).compareToIgnoreCase(pathToStr(p2)));
files.forEach(System.out::println); //They'll be ordered now!
//A method I wrote for pulling this off
public static String pathToStr(File path) {
boolean isDir = path.isDirectory();
String str = path.getAbsolutePath().replace("\\", "/").replace("/", "/\0");
if (!isDir) {
int idx = str.lastIndexOf("/\0");
str = str.substring(0, idx) + str.substring(idx, str.length()).replace("/\0", "/");
}
return str;
}
因此,基本上pathToStr()
所做的是对文件路径进行字符串表示,但有一点曲折:路径中的所有文件夹名称都将以空\0
字符开头。这样,股票字符串排序会将所有子文件夹推到每个文件夹的顶部。只要您没有以null char开头的任何文件名,它就可以正常工作,由于旧C语言处理字符串的能力很好,我什至认为这是不可能的。
另外要注意的是,如果您想以更类似于Unix的方式订购商品,则可以将compareToIgnoreCase
更改为compareTo
,以考虑不同的大小写。
这个问题可能有点老(我写这篇文章的时候已经5岁了),但是我找不到任何不涉及使用库或混合多个比较器的答案,所以一旦我弄清楚了我决定回到这里,加上我的两分钱。享受您保存的下午。
编辑:由于该问题未使用NIO路径,因此我不得不仅使用File
将代码更改为备用版本;但是如果您正在使用像我这样的NIO路径,这是我正在使用的代码:
List<Path> items = Files.walk(rootFolder).collect(Collectors.toList());
items.sort((p1, p2) -> pathToStr(p1).compareToIgnoreCase(pathToStr(p2)));
items.forEach(System.out::println); //They'll be ordered now!
public static String pathToStr(Path path) {
boolean isDir = Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS);
String str = path.toAbsolutePath().toString().replace("\\", "/").replace("/", "/\0");
if (!isDir) {
int idx = str.lastIndexOf("/\0");
str = str.substring(0, idx) + str.substring(idx, str.length()).replace("/\0", "/");
}
return str;
}
无论您是否使用NIO,我们都可以解决。