用多執行緒寫了個硬碟搜尋功能,似乎也只比windows自帶的快以點點。(方法不對嘛)
阿新 • • 發佈:2021-02-19
此時的我必然是剛起床!!!
最近學了多執行緒,想找個小的專案練練手。於是,利用多執行緒寫了一個硬碟搜尋功能。
具體實現是: 實現Runnable介面,使用執行緒池, 個別類使用單例模式。
Results.java : 儲存搜尋結果,運用了單例模式(懶漢式)。
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* @author xiaoxiao
* @date 2021.1.30
* */
public class Results {
private Map<String, String> results; // 儲存 檔名-絕對路徑
private static Results results0;
private Results() {}
public static Results getInstance() { // 單例模式
if (results0 == null) results0 = new Results();
return results0;
}
public boolean put(String fileName, String path) { // 向儲存結構新增搜尋結果
if (this.results == null) {// 第一次新增,為result建立例項物件
this.results = new HashMap<String, String>();
this.results = Collections.synchronizedMap(this.results); // HashMap轉換成安全的容器。
}
this.results.put(fileName, path); // 新增
return true;
}
@Override
public String toString() { // 輸出搜尋結果
StringBuilder s = new StringBuilder("");
int i = 1;
if (results != null)
for (Map.Entry<String, String> entry : this.results.entrySet()) {
s.append(i + " : " + entry.getKey() + " 絕對路徑: " + entry.getValue() + "\n");
++i;
}
else
s.append("未找到該檔案");
return String.valueOf(s); // 將StringBuilder轉換成String
}
}
SearchFiles.java : 實現搜尋功能
import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* @author xiaoxiao
* @date 2021.1.30
* */
public class SearchFiles implements Runnable {
private File beginPath; // 開始路徑
private String target; // 目標檔案
private Results results; // 儲存搜尋結果
private ConcurrentLinkedQueue<File> directories;
private SearchFiles() {
this.directories = new ConcurrentLinkedQueue<File>();
this.results = Results.getInstance();
}
public SearchFiles(String target) { // 預設從C盤中搜索
this();
this.target = target; // 目標檔案
this.beginPath = new File("C:/");
this.directories.add(this.beginPath);
}
public SearchFiles(String beginPath, String target) { // 傳入指定搜尋路徑
this();
this.target = target;
this.beginPath = new File(beginPath); // 指定路徑搜尋
this.directories.add(this.beginPath);
}
// 遞迴搜尋
// public void search(File file) {
// if (file.isFile()) {
// if (file.getName().contains(target)) {
// results.put(file.getName(), file.getAbsolutePath());
// }
// return;
// }
// String[] list = file.list();
// if (list == null) return;
// for (int i = 0; i < list.length; i++) {
// search(new File(file, list[i]));
// }
// }
private boolean flag;
@Override
public void run() {
while (true) {
File file = this.directories.poll();
// 當出現第一個執行緒進入,會把裡面的唯一的元素拿出,此時佇列為空,poll() 返回的就是空,會出現空指標異常,這裡就是在沒有資料時,讓其一直迴圈。
if (file == null) // 避免其他執行緒中斷
continue;
File[] files = file.listFiles();
if (files != null)
for (File file1 : files) {
if (file1.getName().contains(target))
// 如果不想搜尋完後輸出,可以將儲存結果註釋掉,並用輸出檔名和路徑
this.results.put(file1.getName(), file1.getAbsolutePath());
// System.out.println(file1.getName() + " : " + file1.getAbsolutePath());;
// 判斷是否時資料夾,是否有讀寫許可權
if (file1.isDirectory() && file1.canRead() && file1.canWrite())
this.directories.add(file1);
}
// 在這裡判斷
if (this.directories.size() == 0)
break;
}
}
@Override
public String toString() {
return results.toString();
}
}
Main.java : 程式執行
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author xiaoxiao
* @date 2021.1.30
* */
public class Main {
public static void main(String[] args) {
long t = System.currentTimeMillis();
SearchFiles searchFiles = new SearchFiles("D:/",".md");
// searchFiles.search(searchFiles.getBeginPath()); // 這個是遞迴方式, 單執行緒。
ExecutorService service = Executors.newFixedThreadPool(9); // 宣告執行緒池,大小為9
for (int i = 0; i < 9; ++ i) { //
service.execute(searchFiles);
}
service.shutdown();
try { // 等待執行緒池裡的執行緒執行完,在執行主執行緒。
service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
long e = System.currentTimeMillis();
System.out.println(e - t);
System.out.println(searchFiles);
}
}
效果圖:
如果不正確的地方,請大家指出,謝謝!