如何在 java 中应用多线程在目录(主目录和给定的单词)中查找单词并递归地查找其子目录

How to apply multithreading in java to find a word in a directory(main directory and the word given) and recursively its subdirectories

我是 Stack Overflow 的新手,也是 Java 的初学者,所以如果我以不正确的方式提出这个问题,请原谅我。

问题

我有一个作业告诉我使用多线程来搜索给定单词的文件,它可能存在于任何文件中在给定目录(基本上是整个目录)的任何级别上键入 .txt 和 .html。如果文件包含给定的单词,则必须在控制台上显示文件的绝对文件路径。

我尝试了什么

所以我想到把这个任务分成2个部分,分别是Searching和Multithreading, 我能够获得搜索部分( File_search.java )。通过搜索目录并找到给定单词的所有文件,该文件给出了令人满意的结果。

File_search.java

public class File_search{
String fin_output = "";
public String searchInTextFiles(File dir,String search_word) {
    File[] a = dir.listFiles();
    for(File f : a){
        if(f.isDirectory()) {
            searchInTextFiles(f,search_word);
        }
        else if(f.getName().endsWith(".txt") || f.getName().endsWith(".html") || f.getName().endsWith(".htm") ) {
            try {
                searchInFile(f,search_word);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    return fin_output;
}

public void searchInFile(File f,String search_word) throws FileNotFoundException {
    final Scanner sc = new Scanner(f);
    while(sc.hasNextLine()) {
        final String lineFromFile = sc.nextLine();
        if(lineFromFile.contains(search_word)) {
            fin_output += "FILE : "+f.getAbsolutePath().toString()+"\n";
        }
    }
}

现在,我希望能够使用 ThreadPoolExecuter 服务使用多个线程来执行任务 File_search.java。我不确定我是否可以使用 Runnable 、 Callable 或使用 Thread class 或任何其他方法来做到这一点? 你能帮我处理多线程部分的代码吗?谢谢:)

我同意@chrylis -cautiouslyoptimistic 的评论,但出于理解目的,下文会对您有所帮助。

一种更简单的方法是在主线程中遍历目录,我的意思是您在函数 searchInTextFiles 中添加的逻辑,并像在函数 [=12= 中那样执行搜索逻辑] 在一个大小为 10 的线程池中。

下面的示例代码将帮助您更好地理解它。

public class Traverser {

private List<Future<String>> futureList = new ArrayList<Future<String>>();

private ExecutorService executorService;

public Traverser() {
    executorService = Executors.newFixedThreadPool(10);
}

public static void main(String[] args) throws InterruptedException, ExecutionException {
    System.out.println("Started");
    long start = System.currentTimeMillis();
    Traverser traverser = new Traverser();
    traverser.searchInTextFiles(new File("Some Directory Path"), "Some Text");
    
    for (Future<String> future : traverser.futureList) {
        System.out.println(future.get());
    }
    traverser.executorService.shutdown();
    while(!traverser.executorService.isTerminated()) {
        System.out.println("Not terminated yet, sleeping");
        Thread.sleep(1000);
    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken :" + (end - start));
    
}

public void searchInTextFiles(File dir,String searchWord) {
    File[] filesList = dir.listFiles();
    for(File file : filesList){
        if(file.isDirectory()) {
            searchInTextFiles(file,searchWord);
        }
        else if(file.getName().endsWith(".txt") || file.getName().endsWith(".html") || file.getName().endsWith(".htm") ) {
            try {
                futureList.add(executorService.submit(new SearcherTask(file,searchWord)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}}

public class SearcherTask implements Callable<String> {

private File inputFile;
private String searchWord;

public SearcherTask(File inputFile, String searchWord) {
    this.inputFile = inputFile;
    this.searchWord = searchWord;
}


@Override
public String call() throws Exception {
    StringBuilder result = new StringBuilder();
    Scanner sc = null;
    try {
        sc = new Scanner(inputFile);
        while (sc.hasNextLine()) {
            final String lineFromFile = sc.nextLine();
            if (lineFromFile.contains(searchWord)) {
                result.append("FILE : " + inputFile.getAbsolutePath().toString() + "\n");
            }
        }
    } catch (Exception e) {
        //log error
        throw e;
    } finally {
        sc.close();
    }
    return result.toString();
}}