序:一個文件夾下面有很多層的小文件,如何算出這個文件夾下面有多少文件?遞歸遍歷,簡單暴力,遞歸在一般情況確實是比較方便的解決方案,但是當文件夾深度多深,遞歸的反復調用會導致方法一直無法釋放,造成jvm的棧溢出。那我們該怎么辦?
原文和作者一起討論:http://www.cnblogs.com/intsmaze/p/6031894.html
說實話這個問題我以前也沒有遇到過,我是聽一位我很敬佩的IT前輩講的他曾經的面試經歷。他說他當時比較緊張就想到了遞歸,沒有想到其他的方案。
當然他跟我說這個問題的時候,它也沒有想到好的處理方案。它認為這種情況可以參考網絡爬蟲的遞歸,為了防止爬蟲在一個深度出不來,通常會設置每一次爬的深度,然后通過各種的限制條件來保證每一個文件都被訪問到。
當時我靈光一閃,因為當時我在溫故數據結構的知識,我說這個文件夾的層次看着好呀嘛好眼熟,不就相當於一個樹的結構,那我們學數據結構的時候是如何遍歷節點的。有左遞歸,中遞歸,右遞歸,當然這就是上面的遞歸方法,不是我們要找的解決方案,那么該怎么辦?
看,角落里有我們經常忽視的層序遍歷。
層序遍歷:層序遍歷就是從所在樹的根節點出發,首先訪問第一層的樹根節點,然后從左到右訪問第2層上的節點,接着是第三層的節點,以此類推,自上而下,自左至右逐層訪問樹的結點的過程就是層序遍歷。
代碼思路:
我們只需要使用一個list集合來存儲每一個文件(夾),然后按次序讀取list集合的元素,並判斷如果是文件夾則把該文件夾下的所有文件(夾)追加到list集合后面,然后讀取list的下一個元素以此類推。
public class demo { public static void main(String[] args) { List<File> list=new ArrayList<File>(); File file = new File("C:/intsmaze"); list.add(file); for(int i=0;i<list.size();i++) { if(list.get(i).isDirectory()) { File[] tempList = list.get(i).listFiles(); for(int j=0;j<tempList.length;j++) { list.add(tempList[j]); } } } } }
都是有經驗的開發人員,上面的代碼就沒有必要進行注釋了。
當然有人會較真,當文件數量很多,就算這代碼可以保證棧不溢出,但是list集合數量上去了,堆也會爆的。
當然,這是一種情況,其實也很簡單,每從集合讀取一個元素,就把該元素從集合溢出,存入硬盤中即可,然后循環里面的判斷條件中不對i進行遞增即可。
public class demo { public static void main(String[] args) { List<File> list=new ArrayList<File>(); File file = new File("C:/intsmaze"); list.add(file); for(int i=0;i<list.size();) { if(list.get(i).isDirectory()) { File[] tempList = list.get(i).listFiles(); for(int j=0;j<tempList.length;j++) { list.add(tempList[j]); } } list.remove(i); } } }
大家有更好的解決方案可以一起分享討論.