扫描本地文件,或者新插入一个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过滤器不是真的要过滤什么文件,而是用来列出每个文件,然后执行对此文件或者文件夹的执行逻辑。