多线程之文件搜索

多线程之文件搜索

文件搜索是一个很简单的IO操作,单线程的文件搜索代码如下

首先定一个公共类Result,该类主要存储搜索结果,具有两个属性,found和path,found为Boolean值,判断是否查找到文件,path文找到的文件路径

package com.FileSearch;

public class Result {
    private Boolean found;
    private String path;

    public Boolean getFound() {
        return found;
    }

    public void setFound(Boolean found) {
        this.found = found;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}

接下来便是通过递归方法去查找对应的文件名称,代码如下

package com.FileSearch;

import java.io.File;

public class SerialFileSearch {
    public static void searchFiles(File file, String fileName, Result result) {
        File[] contents;
        contents = file.listFiles();

        if((contents == null) || (contents.length == 0)){
            return ;
        }

        for(File content : contents) {
            if(content.isDirectory()) {
                searchFiles(content, fileName, result);
            } else {
//                System.out.println("current content is "+content);
                if(content.getName().equals(fileName)) {
                    result.setPath(content.getAbsolutePath());
                    result.setFound(true);
                    System.out.printf("Serial Search: Path: %s%n",
                            result.getPath());
                    return ;
                }
            }
            if(result.getFound()) {
                return ;
            }
        }
    }
}

现在,我们加上启动类

package com.FileSearch;
import java.io.File;
public class Main {
    public static void main(String[] args) {
        Result result = new Result();
        result.setFound(false);
        File file = new File("/media/");
        long start = System.currentTimeMillis();
        SerialFileSearch.searchFiles(file,"测试文件.txt",result);
        long end = System.currentTimeMillis();
        System.out.println("单线程执行耗时: "+(end - start)+"ms");
    }
}

  上述的代码是对每个目录依次搜索,因此在多线程并发版本中,可以考虑为每一个需要搜索的目录创建一个线程的方法,考虑到I/O操作中一次只有一个线程可以读取磁盘,所以在这里使用和JVM可用内核数相同的线程数。
  在这个方法中,通过ConcurrentLinkedQueue(一个可以在并发应用程序中使用的队列Queue接口实现)用来存储初始路径所包含的目录,并创建和JVM可用处理器相同数量的线程,每个线程将从队列中获取一条路径,并处理该目录及其对应的子目录中的文件。如果其中的一个线程找到的正在查找的文件,终止该线程,并通过interrupt()方法结束其他线程的执行。
  在这里,通过新建PrallelGroupFileTask类,该去实现用于查找文件的线程,该类实现了Runnable接口并且拥有四个内部属性fileName,File对象的ConcurrentLinkedQueue的directories,用于存放要处理的目录列表, Result对象的parallelResult用于存储搜索结果,名为found的boolean属性,标记是否发现了正在寻找的文件信息,代码如下

import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;

public class ParallelGroupFileTask implements Runnable {
    private final String fileName;
    private final ConcurrentLinkedQueue<File> directories;
    private final Result parallelResult;
    private boolean found;

	//构造函数初始化所有的属性
    public ParallelGroupFileTask(String fileName, ConcurrentLinkedQueue<File> directories, Result parallelResult) {
        this.fileName = fileName;
        this.directories = directories;
        this.parallelResult = parallelResult;
        this.found = false;
    }

    @Override
    public void run() {
        while(directories.size() > 0){
            File file = directories.poll(); //取出目录
            try{
                processDirectory(file, fileName, parallelResult);
                if(found) {
                    System.out.printf("%s has found the file%n",Thread.currentThread().getName());
                    System.out.printf("Parallel Search: Path : %s%n", parallelResult.getPath());
                    return ;
                }
            } catch (InterruptedException e) {
                System.out.printf("%s has been interrupted%n", Thread.currentThread().getName());
            }
        }
    }

	//大致的搜索过程和之前的代码一样,
    private void processDirectory(File file, String fileName, Result parallelResult) throws InterruptedException {
        File[] contents = file.listFiles();

        if((contents == null) || (contents.length == 0)) {
            return ;
        }

        for(File content : contents) {
            if(content.isDirectory()) {
                processDirectory(content, fileName, parallelResult);
                if(Thread.currentThread().isInterrupted()) {
                    throw new InterruptedException();
                }
                if(found) {
                    return ;
                }

            } else {
                processFile(content,fileName,parallelResult);
                if(Thread.currentThread().isInterrupted()){
                    throw new InterruptedException();
                }
                if(found){
                    return ;
                }
            }
        }
    }

	//文件名称对比函数而以
    private void processFile(File content, String fileName, Result parallelResult) {
        if(content.getName().equals(fileName)) {
            parallelResult.setPath(content.getAbsolutePath());
            this.found = true;
        }
    }

    public boolean getFound() {
        return found;
    }
}

  通过新建一个类ParallelGroupFIleSearch来创建线程并辅助算法完成,代码设计如下

import java.io.File;
import java.util.concurrent.ConcurrentLinkedQueue;

public class ParallelGroupFileSearch {
    public static void searchFiles(File file, String fileName, Result parallelResult){
        ConcurrentLinkedQueue<File> directories = new ConcurrentLinkedQueue<>();
        File[] conients = file.listFiles();

        for(File content: conients) {
            if(content.isDirectory()) {
                directories.add(content);
            }
        }

        int numThreads = Runtime.getRuntime().availableProcessors(); //获取可用的线程数量
        Thread[] threads = new Thread[numThreads];

        ParallelGroupFileTask[] tasks = new ParallelGroupFileTask[numThreads];

        for(int i=0;i<numThreads; i++) {   //写入数组中
            tasks[i] = new ParallelGroupFileTask(fileName , directories , parallelResult);
            threads[i] = new Thread(tasks[i]);
            threads[i].start();
        }

        boolean finish = false;

        int numFinished = 0;

        while(!finish) {
            numFinished = 0;
            for(int i=0; i<threads.length; i++) {
                if(threads[i].getState() == Thread.State.TERMINATED) {
                    numFinished++;
                    if(tasks[i].getFound()) {
                        finish = true;
                    }
                }
            }
            if(numFinished == threads.length) { //当所有的线程都执行完,则停止
                finish = true;
            }
        }

        //如果numFinished比length小,则证明查找到文件
        //取消全部进程
        if(numFinished != threads.length) { 
            for(Thread thread : threads) {
                thread.interrupt();
            }
        }
    }
}

最后启动类如下

import java.io.File;

public class Main {
    public static void main(String[] args) {
        Result result = new Result();
        result.setFound(false);
        File file = new File("/media/");
        long start = System.currentTimeMillis();
        ParallelGroupFileSearch.searchFiles(file,"测试文件.txt",result);
        long end = System.currentTimeMillis();
        System.out.println("多线程执行耗时: "+(end - start)+"ms");
    }
}

以上就是所线程文件搜索的整个内容,测试完之后发现的确比单线程快很多啊!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,可以使用多线程来查找文件。以下是一个简单的示例代码: ```java import java.io.File; import java.util.ArrayList; import java.util.List; public class FileSearch implements Runnable { private String fileName; private String searchDir; private List<String> result; public FileSearch(String fileName, String searchDir) { this.fileName = fileName; this.searchDir = searchDir; this.result = new ArrayList<>(); } @Override public void run() { search(new File(searchDir)); } private void search(File file) { if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null) { for (File f : files) { search(f); } } } else { if (file.getName().equals(fileName)) { result.add(file.getAbsolutePath()); } } } public List<String> getResult() { return result; } } ``` 在上面的代码中,我们定义了一个名为`FileSearch`的类,实现了`Runnable`接口。在`run`方法中,我们使用递归的方式遍历指定目录下的所有文件文件夹。 当遍历到文件时,我们将文件名与指定的要查找的文件名进行比较,如果相同,则将该文件的绝对路径添加到结果列表中。 使用时,可以创建多个`FileSearch`对象,并将其作为线程启动。每个线程将在指定目录下查找指定文件,并将结果保存在各自的结果列表中。 以下是一个示例的使用代码: ```java public class Main { public static void main(String[] args) { String searchDir = "path/to/search/directory"; String fileName = "file_to_search.txt"; FileSearch search1 = new FileSearch(fileName, searchDir); FileSearch search2 = new FileSearch(fileName, searchDir); Thread thread1 = new Thread(search1); Thread thread2 = new Thread(search2); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } List<String> result1 = search1.getResult(); List<String> result2 = search2.getResult(); System.out.println("Search results from thread 1:"); for (String path : result1) { System.out.println(path); } System.out.println("Search results from thread 2:"); for (String path : result2) { System.out.println(path); } } } ``` 在上面的代码中,我们创建了两个`FileSearch`对象,并分别启动了两个线程进行搜索。最后,我们输出了每个线程的搜索结果。 注意:以上代码仅为示例,实际使用时可能需要添加异常处理、文件过滤等逻辑。另外,多线程查找文件时,要注意线程安全性和资源竞争的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值