磁碟搜尋之Java簡單實現
引言:在使用電腦的時候,難免會遇到找不到本地檔案的情況,而我們通常又記得檔名或者其中的幾個關鍵字。當然一般系統都提供搜尋方法,如windows的搜尋,但其不全是基於檔名的,因而搜尋效率顯得低下。在基於檔名的檔案搜尋模式下,市面上有優秀的成品軟體---著名的Everything,其原理我不多說了,簡單一查就明白。下面我就談談我們用Java實現的一種基於檔名的檔案搜尋,希望大家提出更好的修改意見~~
1. 總的思路:先將檔案系統的所有檔名(帶路徑)讀入記憶體;再組織成一定資料結構的索引(方便檢索用);同時新增監聽器,響應檔案系統的變化;退出時,將記憶體中對應的索引資訊壓縮儲存到硬碟上;再次啟動時,先從硬碟讀入檔名資訊、處理,然後在後臺掃描磁碟,更新索引。
2. 檔名資訊的獲取:掃描全盤,可以採用遞迴或非遞迴的辦法。如下非遞迴掃描:
Stack<String> folderStack = newStack<String>();//存放資料夾的臨時棧
File[] roots = File.listRoots();//獲取所有磁碟碟符
for (int i = roots.length - 1; i >= 0; i--)
folderStack.push(roots[i].toString());
while (!folderStack.isEmpty())// 遍歷
{
File[] fl = new File(folderStack.pop()).listFiles();
if (fl == null)
continue;
for (int i = 0; i < fl.length; i++) {
if (fl[i].isDirectory()) {
folderStack.push(fl[i].getAbsolutePath());
} else {
index.add(fl[i].getAbsolutePath());
}
}
}
該方法實現簡單,但是效率低下。一種優化辦法可以是借鑑Everything的方法,用C/C++寫一個dll,在java程式碼裡呼叫,後臺執行。
3. 資料結構:改寫的HashMap,其Key-Value型別是<String,ArrayList>。為了插入、刪除的方便,我們改寫了它此部分的實現:
public boolean put(String key, String value)
{
if(key == null)
return false;
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for(Entry e = table[i]; e!=null; e=e.next)
{
/*
* 處理當前key已存在於hashMap的情況
*/
if(e.hash == hash&&(key.equals(e.key)))
{
/*
* 若value列表中存在當前value,插入失敗
*/
if(e.value.contains(value))
return false;
e.value.add(value);
size++;
return true;
}
}
modCount++;
size++;
addEntry(hash,key,value,i);
return true;
}
刪除實現在此就不列舉了。考慮到一般電腦檔案系統的檔案數在10W以上的數量級,我們在確定HashMap的初始容量時需特別考慮,它直接影響構建Map的效率。
採用此HashMap帶來的問題是:若是檔案的全名,則可以根據檔名的雜湊值直接找到Value;否則,需要遍歷整個Map;若要支援正則查詢,需要處理查詢條件,仍需遍歷整個Map。
4. 監聽器:由於檔案系統的檔案可以隨時變化,所以在程式執行期間,我們需要檢測其變化,並作出響應。這裡,我們採用JNotify來實現。利用JNotify和Java多執行緒,我們完成了對多個磁碟的監聽和處理。
5. 索引壓縮儲存:由於我們時間有限,直接採用了Java 包裡提供的zip壓縮,最終將幾十兆的索引檔案壓縮到十兆之內。實際上,考慮到這些索引中以英文居多,我們可以採用更有效地壓縮演算法。
好了,就先寫這麼多吧。希望大家提出更好的辦法~~