java實現遍歷磁盤文件中遞歸調用和非遞歸調用性能比較和使用SimpleFileVisitor性能比較

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秒(這個方法找了很長時間傷心)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章