面对扫描指定目录下全部文件以获取特定文件的需求的时候,我们最常用的解决思路是递归查找算法,如果对递归逻辑不清晰往往造成递归过程无终止、或者受限系统堆栈及内存大小导致不能做更深层次的递归,从JAVA 1.7后Files类做了重大增补,采用了更为优雅和高性能的方式解决了这些问题,下面就对比两种实现方式,从而推荐大家今后使用java的Files新特效更好的解决这个问题。
传统递归方式
这种方式是从一个目录作为入口,逐层扫描子目录,将符合条件的文件搜索出来进行处理,直到扫描结束,每遇到一个目录就调用递归方法,在递归方法里边设置递归结束条件。例如:要搜索指定目录下所有的java源代码文件。
//遍历指定目录下的全部文件
public void find(String pathName) {
//获取pathName的File对象
File dirFile = new File(pathName);
//判断是否有读权限
if (!dirFile.canRead()){
log.info("do not read");
return;
}
if (!dirFile.isDirectory()) {
String fileType=fileType(dirFile,JUDGE);
if(FILETYPE.contains(fileType)) {
destFile.add(dirFile);
}
}
else {
//获取此目录下的所有文件名与目录名
String[] fileList = dirFile.list();
for (String subFile : fileList) {
File file = new File(dirFile.getPath(), subFile);
if (!file.canRead()) {
continue;
}
//如果是一个目录,输出目录名后,进行递归
if (file.isDirectory()) {
if(fileType(file, JUDGE).equals("link")) continue;
//递归
try {
find(file.getCanonicalPath());
} catch (Exception e) {
log.error("{}", e.getLocalizedMessage());
}
}
else {
//忽略掉临时文件,以~$起始的文件名
if (file.getName().startsWith("~$")) continue;
if (FILETYPE.contains(fileType(file, JUDGE))) {
log.info("{}",file.getName());
}
}
}
}
}
Files类的walkFileTree方法
Files静态类的这个方法以非常优雅的方式实现了上面的传统功能,不仅代码量非常少,而且思维模式更接近人类常规思维,采用了事件响应的方式处理每一个遍历到的文件。
//利用File的walkFileTree方法实现文件遍历
public void filterFile(String pathName) throws IOException{
Files.walkFileTree(Paths.get(pathName), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
File file=path.toFile();
String fileType=fileType(file,JUDGE);
if(file.isFile() && !path.startsWith("~$") && FILETYPE.contains(fileType)) {
log.info("{}",file.getName());
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc){
return FileVisitResult.CONTINUE;
}
});
}