此时的我必然是刚起床!!!
最近学了多线程,想找个小的项目练练手。于是,利用多线程写了一个硬盘搜索功能。
具体实现是: 实现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() + "
");
++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);
}
}
效果图:
如果不正确的地方,请大家指出,谢谢!