1.说明一下,我的电脑中的磁盘目录是一个文件夹,并且是个隐藏的文件夹.
每一个磁盘中都有隐藏的文件夹,通过 File.listFiles()方法,返回的文件或者文件夹其中存在电脑上看不到但是实际存在的隐藏的文件夹,当对这个隐藏的文件使用new File的时候会出现空指针,因为这些文件夹不可以访问,备注:在C盘中不仅存在隐藏的文件夹,还存在一种其他类型的文件夹,也是电脑上看不到但是实际存在的系统文件或者文件夹.
2.比较递归调用和非递归调用遍历磁盘的性能.
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
public class FolderFileScanner {
public static LinkedList<File> queueFiles = new LinkedList<File>();
public static ArrayList<Object> scanFiles = new ArrayList<Object>();
public static void main(String[] args)throws Exception {
//测试速度:
String str="G:\\";
/*File directory = new File(str);
if(directory.isDirectory()){
System.out.println("为文件夹");
}else{
System.out.println("非文件夹");
}
if(directory.isHidden()){
System.out.println("该文件为隐藏文件");
}
File [] filelist = directory.listFiles();
for(int i = 0; i < filelist.length; i ++){
if(filelist[i].isHidden()){
System.out.println("隐藏文件"+filelist[i].getAbsolutePath());
}
// System.out.println(filelist[i].getAbsolutePath());
}*/
long startTime=System.currentTimeMillis();
scanFilesWithRecursion(str);
long endTime=System.currentTimeMillis();
System.out.println("递归调用耗时:"+(endTime-startTime)+"毫秒");
System.out.println("递归调用文件数据:"+scanFiles.size());
scanFiles.clear();
queueFiles.clear();
//非递归调用
long start=System.currentTimeMillis();
scanFilesWithNoRecursion(str);
long end=System.currentTimeMillis();
System.out.println("采用非递归调用耗时"+(end-start)+"毫秒");
}
/**
* TODO:递归扫描指定文件夹下面的指定文件
*/
public static ArrayList<Object> scanFilesWithRecursion(String folderPath) throws Exception{
ArrayList<String> dirctorys = new ArrayList<String>();
File directory = new File(folderPath);
if(!directory.isDirectory()){
System.out.println("不是目录");
}
if(directory.isDirectory()){
//System.out.println("递归调用");
File [] filelist = directory.listFiles();
for(int i = 0; i < filelist.length; i ++){
/**如果当前是文件夹,进入递归扫描文件夹**/
if(filelist[i].isDirectory()&&(!filelist[i].isHidden())){
dirctorys.add(filelist[i].getAbsolutePath());
/**递归扫描下面的文件夹**/
scanFilesWithRecursion(filelist[i].getAbsolutePath());
}
/**非文件夹**/
else{
scanFiles.add(filelist[i].getAbsolutePath());
}
}
}
return scanFiles;
}
/**
*
* TODO:非递归方式扫描指定文件夹下面的所有文件
*/
public static ArrayList<Object> scanFilesWithNoRecursion(String folderPath) throws Exception{
File directory = new File(folderPath);
if(directory.isDirectory()){
//首先将第一层目录扫描一遍
File [] files = directory.listFiles();
//遍历扫出的文件数组,如果是文件夹,将其放入到linkedList中稍后处理
for(int i = 0; i < files.length; i ++){
if(files[i].isDirectory()&&(!files[i].isHidden())){
queueFiles.add(files[i]);
//System.out.println(files[i].getAbsolutePath());
}else{
//暂时将文件名放入scanFiles中
scanFiles.add(files[i].getAbsolutePath());
}
}
//如果linkedList非空遍历linkedList
while(!queueFiles.isEmpty()){
//移出linkedList中的第一个
File headDirectory = queueFiles.removeFirst();
File [] currentFiles = headDirectory.listFiles();
for(int j = 0; j < currentFiles.length; j ++){
if(currentFiles[j].isDirectory()){
//如果仍然是文件夹,将其放入linkedList中
queueFiles.add(currentFiles[j]);
}else{
scanFiles.add(currentFiles[j].getAbsolutePath());
}
}
}
}else{
System.out.println("不是目录");
}
System.out.println("非递归调用文件数据:"+scanFiles.size());
return scanFiles;
}
}
运行结果:
还是非递归调用的性能更佳,因为当文件夹树存在的级别越多,那么递归调用的迭代次数会原来越多,导致性能不断的降低.
3.关于文件的注意事项
例如:我们创建一个文件(非文件夹) aaa.txt;
这段代码可以执行虽然该文件不是文件夹 File[] files=(new File("F:\\aaa.txt")).listFiles();
但是如果我们使用files的任意方法,或者访问files就会报空指针异常.
对于系统文件或者隐藏的文件,无法访问的文件,可以执行后去listFile,但是获取的对象不能够操作,否者报错.
4.下面测试使用SimpleFileVisitor来运行
FileFinder2类
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FilterMp3 {
private static List<File> musicList2 = new ArrayList<>();
private String filterD = "C:\\";
//遍历方法2:改遍历方式为深度优先遍历
private List<File> getMp3FromeFileVisitor() throws IOException{
long start2 = System.currentTimeMillis();
Files.walkFileTree(Paths.get(filterD), new SimpleFileVisitor<Path>(){
@Override// 正在访问一个文件时要干啥
public FileVisitResult visitFile(Path file,BasicFileAttributes attrs){
musicList2.add(file.toFile());
return FileVisitResult.CONTINUE;
}
@Override//访问一个目录前要干啥
public FileVisitResult preVisitDirectory(Path dir,BasicFileAttributes attrs){
musicList2.add(dir.toFile());
return FileVisitResult.CONTINUE;
}
//@Override//访问一个目录后要干嘛
public FileVisitResult postVisitDirectory(Path dir,BasicFileAttributes attrs){
return FileVisitResult.CONTINUE;
}
@Override//访问一个文件失败时要做什么
public FileVisitResult visitFileFailed(Path file,IOException e){
return FileVisitResult.CONTINUE;
}
});
long end2 = System.currentTimeMillis();
System.out.println("方法2结果:" + musicList2.size()+" " + "用时:" +(end2 - start2) +"ms");
return musicList2;
}
public static void main(String[] args) {
FilterMp3 fm = new FilterMp3();
try {
fm.getMp3FromeFileVisitor();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0;i<musicList2.size();i++){
///System.out.println("文件:"+musicList2.get(i).toString());
}
}
}
运行结果:扫描24万个文件用时仅仅7秒(这个方法找了很长时间伤心)