掃描本地文件,或者新插入一個U盤,怎麼用一種比較合理算法去掃描整個盤符,獲取到想要的文件呢?比如音樂、視頻、圖片文件等。大致的思路肯定是從根節點開始掃描,然後遞歸掃描整個文件,最後形成一個樹形結構,文件就存在於這些樹枝當中。
首先需要定義數據結構。
1、文件夾的數據結構:
FolderNode{
private String mPath; //絕對路徑
private FolderNode parent; //父節點
private TreeMap<String,FolderNode> childs; //子節點
private List<FileNode> musics; //音樂相關文件集合
private List<FileNode> videos; //視頻相關文件集合
}
2、文件的數據結構:
FileNode{
private String mPath; //絕對路徑
private FolderNode parent; //父節點
public String id3_album = "";//歌手(非必須)
public String id3_artist = "";//專輯(非必須)
public String id3_title = "";//歌名(非必須)
}
掃描文件是從根節點開始的,那麼首先需要構建一個根節點
private FolderNode usbRoot = new FolderNode(USB_ROOT);
掃描一個盤符,是把每一級的掃描任務分解成一個個run,放到線程池中去併發執行。但在做這些之前,我們先要定義一個子線程來開啓和管理後面遞歸掃描時出發的多線程。不然由於是多線程,就不知道各個線程的執行情況。
class ScanThread extends Thread{
FolderNode folderNode;
int mAddTaskNumber,mExuteTaskNumber;//定義一個增加線程的數量,一個執行完線程的數量
public ScanThread(FolderNode folderNode){
this.folderNode = folderNode;
}
@Override
public void run(){
scan(folderNode,this);
}
}
san(final FolderNode pNode,final ScanThread scanThread){
synchronized (scanThread.mLock){
scanThread.mAddTaskNumber ++;
}
Runnable stubRunnable = new Runnable{
@Override
public void run() {
File file = new File(pNode.mPath);
file.listFiles( new FileFilter(){
@Override
public boolean accept(File file) {
if(file.isDirectory()){
//如果是文件夾,繼續遞歸掃描
FolderNode childNode = new FolderNode(file);
childNode.parent = pNode;
scan(childNode);
}else{
//如果是具體文件,則不用再遞歸
FileNode mNode = new FileNode(file,pNode);
switch(ScanUtil.getTypeByPath(mNode.getPath())){
case MUSIC:
pNode.addMusic(mNode);
case VIDEO:
pNode.addVideo(mNode);
}
}
return false;
});
pNode.setScanFinish(true);
synchronized(scanThread.mLock){
scanThread.mExuteTaskNumber ++;
if(scanThread.mAddTaskNumber == scanThread.mExuteTaskNumber){
//根目錄下的所有文件已經掃描完畢
}
}
}
};
mThreadPoolExecutor.execute(stubRunnable);
}
上面的FileFilter過濾器不是真的要過濾什麼文件,而是用來列出每個文件,然後執行對此文件或者文件夾的執行邏輯。