Java ファイルのスキャンと複数のファイル内の文字列の検索

序文

ディレクトリ (サブディレクトリを含む) にあるファイルをスキャンしたい場合、またはフォルダー内のすべてのファイルの内容を検索し、どのファイルのどの行にキーワード「xxx」が含まれているかを検索したい場合は、この記事が役立ちます。

1. ツール



import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class SearchWord {
    
    

   //当在文件夹中搜索时,遇到以下非文本文件则跳过
    public static List<String> excludeFileType = Arrays.asList(
            "jar", "zip", "rar", "7z", "tar", "gz", "xz", "bz2", "doc", "class", "pak",
            "xls", "ppt", "pdf", "docx", "xlsx", "pptx", "jpg", "jpge", "gif", "png",
            "xltd", "war", "hprof", "m4a", "swf", "mobi", "jpeg", "tiff", "svg", "psd",
            "mp3", "aac", "mp4", "avi", "flv", "mkv", "mpeg", "msi", "tgz", "mdf",
            "rmvb", "apk", "ts", "map", "car", "mov", "wav", "raw", "dll", "woff",
            "eot", "otf", "ico", "ttf", "ttc", "fon", "dl_", "pd_", "ex_", "etl",
            "sys", "iso", "isz", "esd", "wim", "gho", "dmg", "mpf", "exe", "ldf");

    /**
     * 搜索指定文件中的关键字
     *
     * @param filePath  要搜索的文件路径
     * @param searchStr 要搜索的关键字
     * @return 返回的 map<行数, 该行内容>
     */
    public static Map<Integer, String> scanFile(String filePath, String searchStr) {
    
    
        Map<Integer, String> map = new LinkedHashMap<>();
        FileInputStream file = null; //读取文件为字节流
        try {
    
    
            file = new FileInputStream(filePath);
            InputStreamReader in = new InputStreamReader(file, StandardCharsets.UTF_8); //字节流转化为字符流,以GBK读取防止中文乱码
            BufferedReader buf = new BufferedReader(in); //加入到缓存区
            String str = "";
            int row = 1;
            while ((str = buf.readLine()) != null) {
    
     //按行读取,到达最后一行返回null
                if (str.contains(searchStr)) {
    
    
                    map.put(row, str);
                }
                row++;
            }
            buf.close();
            file.close();
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 扫描dirPath下所有文件
     *
     * @param dirPath 要搜索的文件夹路径
     * @return 返回所有文件的路径
     */
    public static List<String> getAllFilesPath(String dirPath) {
    
    
        List<String> list = new ArrayList<>();
        return getAll_FilesPath(dirPath, list);
    }

    /**
     * 扫描dirPath下所有文件
     *
     * @param dirPath    要搜索的文件夹路径
     * @param excludeDir 不扫描的文件夹名列表
     * @return 返回所有文件的路径
     */
    public static List<String> getAllFilesPathEx(String dirPath, List<String> excludeDir) {
    
    
        List<String> list = new ArrayList<>();
        return getAll_FilesPath(dirPath, list, excludeDir);
    }

    /**
     * 扫描dirPath下的所有文件类型是fileType的文件
     *
     * @param dirPath  要搜索的文件夹路径
     * @param fileType 文件后缀,要扫描的文件的类型
     * @return 返回所有fileType类型文件的路径
     */
    public static List<String> getAllFilesPath(String dirPath, List<String> fileType) {
    
    
        List<String> list = new ArrayList<>();
        return getAllFiles(dirPath, fileType, list);
    }

    /**
     * 扫描dirPath下的所有文件类型是fileType的文件
     *
     * @param dirPath    要搜索的文件夹路径
     * @param fileType   文件后缀,要扫描的文件的类型
     * @param excludeDir 不扫描的文件夹名列表
     * @return 返回所有fileType类型文件的路径
     */
    public static List<String> getAllFilesPath(String dirPath, List<String> fileType, List<String> excludeDir) {
    
    
        List<String> list = new ArrayList<>();
        return getAllFiles(dirPath, fileType, list, excludeDir);
    }

    /**
     * @param dirPath   要搜索的文件夹路径
     * @param searchStr 要搜索的关键字
     * @param fileType  要搜索的文件后缀
     * @return <文件名, <行数, 该行内容>>
     */
    public static Map<String, Map<Integer, String>> searchFiles(String dirPath, String searchStr, List<String> fileType) {
    
    
        return searchFiles(dirPath, searchStr, fileType, null);
    }

    /**
     * @param dirPath    要搜索的文件夹路径
     * @param searchStr  要搜索的关键字
     * @param fileType   要搜索的文件后缀
     * @param excludeDir 不扫描的文件夹名列表
     * @return <文件名, <行数, 该行内容>>
     */
    public static Map<String, Map<Integer, String>> searchFiles(String dirPath, String searchStr, List<String> fileType, List<String> excludeDir) {
    
    
        List<String> allFiles = excludeDir == null || excludeDir.size() == 0 ? getAllFilesPath(dirPath, fileType) : getAllFilesPath(dirPath, fileType, excludeDir);
        Map<String, Map<Integer, String>> searchInfo = new LinkedHashMap<>();
        for (String f : allFiles) {
    
    
            System.out.println("正在文件中搜索,当前搜索文件:" + f);
            Map<Integer, String> map = scanFile(f, searchStr);
            if (map.size() != 0) {
    
    
                searchInfo.put(f, map);
            }
        }
        return searchInfo;
    }


    /**
     * 搜索文件夹下所有可读文件中是否含有要查找的关键字
     *
     * @param dirPath   要搜索的文件夹路径
     * @param searchStr 要搜索的关键字
     * @return <文件名, <行数, 该行内容>>
     */
    public static Map<String, Map<Integer, String>> searchAllFiles(String dirPath, String searchStr) {
    
    
        return searchAllFiles(dirPath, searchStr, null);
    }

    /**
     * 搜索文件夹下所有可读文件中是否含有要查找的关键字
     *
     * @param dirPath    要搜索的文件夹路径
     * @param searchStr  要搜索的关键字
     * @param excludeDir 不扫描的文件夹名列表
     * @return <文件名, <行数, 该行内容>>
     */
    public static Map<String, Map<Integer, String>> searchAllFiles(String dirPath, String searchStr, List<String> excludeDir) {
    
    
        List<String> allFiles = excludeDir == null || excludeDir.size() == 0 ? getAllReadFilessPath(dirPath, new ArrayList<>(), null) : getAllReadFilessPath(dirPath, new ArrayList<>(), excludeDir);
        Map<String, Map<Integer, String>> searchInfo = new LinkedHashMap<>();
        for (String f : allFiles) {
    
    
            System.out.println("正在文件中搜索,当前搜索文件:" + f);
            Map<Integer, String> map = scanFile(f, searchStr);
            if (map.size() != 0) {
    
    
                searchInfo.put(f, map);
            }
        }
        return searchInfo;
    }

    /**
     * @param dirPath   要搜索的文件夹路径
     * @param searchStr 要搜索的关键字
     * @param fileType  要搜索的文件后缀
     * @return <文件名, <行数, 该行内容>>
     */
    public static void searchAndPrint(String dirPath, String searchStr, List<String> fileType) {
    
    
        Map<String, Map<Integer, String>> map = SearchWord.searchFiles(dirPath, searchStr, fileType);
        for (Map.Entry<String, Map<Integer, String>> m : map.entrySet()) {
    
    
            System.out.println("文件路径: " + m.getKey());
            for (Map.Entry<Integer, String> n : m.getValue().entrySet()) {
    
    
                System.out.println("第" + n.getKey() + "行:" + n.getValue());
            }
            System.out.println();
        }
    }

    //获取所有的文件路径,excludeDir是要跳过查询的文件夹名列表
    public static List<String> getAllReadFilessPath(String dirPath, List<String> list, List<String> excludeDir) {
    
    
        File file = new File(dirPath);
        File[] tempList = file.listFiles();
        System.out.println("正在扫描文件夹:" + dirPath);
        if (null != tempList) {
    
    
            for (int i = 0; i < tempList.length; i++) {
    
    
                String filePath = tempList[i].toString();
                String file_Type = filePath.substring(filePath.lastIndexOf(".") + 1);
                if (tempList[i].isFile()) {
    
    
                    //如果是可读的文本文件
                    if (!excludeFileType.contains(file_Type)) {
    
    
                        list.add(filePath);
                    }
                } else {
    
    
                    if (excludeDir == null || excludeDir.size() == 0) {
    
    
                        getAllReadFilessPath(filePath, list, excludeDir);
                    } else {
    
    
                        String dirName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
                        if (!excludeDir.contains(dirName)) {
    
    
                            //如果是文件夹则递归
                            getAllReadFilessPath(filePath, list, excludeDir);
                        }
                    }
                }
            }
        }
        return list;
    }

    //获取文件夹下所有的文件路径,excludeDir是要跳过查询的文件夹名列表
    public static List<String> getAll_FilesPath(String dirPath, List<String> list, List<String> excludeDir) {
    
    
        File file = new File(dirPath);
        File[] tempList = file.listFiles();
        System.out.println("正在扫描文件夹:" + dirPath);
        if (null != tempList) {
    
    
            for (int i = 0; i < tempList.length; i++) {
    
    
                String filePath = tempList[i].toString();
                if (tempList[i].isFile()) {
    
    
                    list.add(filePath);
                } else {
    
    
                    //如果是文件夹则递归
                    if (excludeDir == null || excludeDir.size() == 0) {
    
    
                        getAll_FilesPath(filePath, list);
                    } else {
    
    
                        String dirName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
                        if (!excludeDir.contains(dirName)) {
    
    
                            //如果是文件夹则递归
                            getAll_FilesPath(filePath, list, excludeDir);
                        }
                    }
                }
            }
        }
        return list;
    }

    //获取文件夹下所有的文件路径
    public static List<String> getAll_FilesPath(String path, List<String> list) {
    
    
        return getAll_FilesPath(path, list, null);
    }

    //获取所有的文件路径,fileType是所有要查询的文件类型
    public static List<String> getAllFiles(String dirPath, List<String> fileType, List<String> list) {
    
    
        return getAllFiles(dirPath, fileType, list, null);
    }

    //获取所有的文件路径,fileType是所有要查询的文件类型,excludeDir是要跳过查询的文件夹名列表
    public static List<String> getAllFiles(String dirPath, List<String> fileType, List<String> list, List<String> excludeDir) {
    
    
        File file = new File(dirPath);
        File[] tempList = file.listFiles();
        System.out.println("正在扫描文件夹:" + dirPath);
        if (null != tempList) {
    
    
            for (int i = 0; i < tempList.length; i++) {
    
    
                String filePath = tempList[i].toString();
                String file_Type = filePath.substring(filePath.lastIndexOf(".") + 1);
                if (tempList[i].isFile()) {
    
    
                    //如果是文件
                    if (fileType.contains(file_Type)) {
    
    
                        list.add(filePath);
                    }
                } else {
    
    
                    if (excludeDir == null || excludeDir.size() == 0) {
    
    
                        getAllFiles(filePath, fileType, list);
                    } else {
    
    
                        String dirName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
                        if (!excludeDir.contains(dirName)) {
    
    
                            //如果是文件夹则递归
                            getAllFiles(filePath, fileType, list, excludeDir);
                        }
                    }
                }
            }
        }
        return list;
    }
}



2. フォルダー内のすべてのファイルをスキャンします

D:\Xunlei Download\フォルダー内のすべてのファイルをスキャンします

    public static void main(String[] args) {
    
    
        String dir = "D:\\迅雷下载\\";
        List<String> filesPath = SearchWord.getAllFilesPath(dir);
        filesPath.forEach(System.out::println);
    }

出力:

D:\迅雷下载\1623720138.rar
D:\迅雷下载\codeNotes-master.zip
D:\迅雷下载\DittoSetup_64bit_3_24_184_0.exe
D:\迅雷下载\eclipse-inst-jre-win64.exe
D:\迅雷下载\eclipse-jee-2021-09-R-win32-x86_64.zip
D:\迅雷下载\fastjson-1.2.76.jar
D:\迅雷下载\guava-30.1.1-jre.jar
D:\迅雷下载\ideaIU-213.5605.12.exe
D:\迅雷下载\imageglass_8.2.6.6_x64.msi
D:\迅雷下载\latest-win64.zip.xltd
D:\迅雷下载\latest-win64.zip.xltd.cfg
D:\迅雷下载\layDate-v5.3.1\laydate\laydate.js
D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\font\iconfont.woff
D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\laydate.css
D:\迅雷下载\layDate-v5.3.1\test.html
D:\迅雷下载\layDate-v5.3.1\文档\文档.url
D:\迅雷下载\layDate-v5.3.1\更新日志.url
D:\迅雷下载\layDate-v5.3.1.zip
D:\迅雷下载\springboot-demo-maven-master.zip
D:\迅雷下载\yx12345sqlyog.rar
D:\迅雷下载\新建文件夹\ideaIU-2021.1.1.exe
D:\迅雷下载\新建文件夹\note.txt

3. フォルダー内のすべてのファイルをスキャンし、指定したフォルダーを除外します

D:\Xunlei Download\ フォルダー内のすべてのファイルをスキャンします。「layDate-v5.3.1」フォルダー内のファイルはスキャンしません。

    public static void main(String[] args) {
    
    
        String dir = "D:\\迅雷下载\\";
        List<String> excludeDir = Arrays.asList("layDate-v5.3.1");
        List<String> filesPath = SearchWord.getAllFilesPathEx(dir,excludeDir);
        filesPath.forEach(System.out::println);
    }

出力:

D:\迅雷下载\1623720138.rar
D:\迅雷下载\codeNotes-master.zip
D:\迅雷下载\DittoSetup_64bit_3_24_184_0.exe
D:\迅雷下载\eclipse-inst-jre-win64.exe
D:\迅雷下载\eclipse-jee-2021-09-R-win32-x86_64.zip
D:\迅雷下载\fastjson-1.2.76.jar
D:\迅雷下载\guava-30.1.1-jre.jar
D:\迅雷下载\ideaIU-213.5605.12.exe
D:\迅雷下载\imageglass_8.2.6.6_x64.msi
D:\迅雷下载\latest-win64.zip.xltd
D:\迅雷下载\latest-win64.zip.xltd.cfg
D:\迅雷下载\layDate-v5.3.1.zip
D:\迅雷下载\springboot-demo-maven-master.zip
D:\迅雷下载\yx12345sqlyog.rar
D:\迅雷下载\新建文件夹\ideaIU-2021.1.1.exe
D:\迅雷下载\新建文件夹\note.txt

4. フォルダー内の指定された種類のファイルをスキャンします

D:\Xunlei Download\フォルダーをスキャンして、jar、zip、txt ファイルを探します

    public static void main(String[] args) {
    
            
        String dir = "D:\\迅雷下载\\";
        List<String> filesType = Arrays.asList("jar","zip","txt");
        List<String> filesPath = SearchWord.getAllFilesPath(dir,filesType);
        filesPath.forEach(System.out::println);
     }

出力:

D:\迅雷下载\codeNotes-master.zip
D:\迅雷下载\eclipse-jee-2021-09-R-win32-x86_64.zip
D:\迅雷下载\fastjson-1.2.76.jar
D:\迅雷下载\guava-30.1.1-jre.jar
D:\迅雷下载\layDate-v5.3.1.zip
D:\迅雷下载\springboot-demo-maven-master.zip
D:\迅雷下载\新建文件夹\note.txt

5. フォルダー内の指定されたタイプのファイルをスキャンし、指定されたフォルダーを除外します。

D:\Xunlei Download\ フォルダーで jar、zip、および txt ファイルをスキャンします。「新しいフォルダー」という名前のフォルダーがある場合、このフォルダーの下にあるファイルはスキャンされません

    public static void main(String[] args) {
    
            
        String dir = "D:\\迅雷下载\\";
        List<String> filesType = Arrays.asList("jar","zip","txt");
        List<String> excludeDir = Arrays.asList("新建文件夹");
        List<String> filesPath = SearchWord.getAllFilesPath(dir,filesType,excludeDir);
        filesPath.forEach(System.out::println);
     }

出力:

D:\迅雷下载\codeNotes-master.zip
D:\迅雷下载\eclipse-jee-2021-09-R-win32-x86_64.zip
D:\迅雷下载\fastjson-1.2.76.jar
D:\迅雷下载\guava-30.1.1-jre.jar
D:\迅雷下载\layDate-v5.3.1.zip
D:\迅雷下载\springboot-demo-maven-master.zip

6. 指定したファイル内の文字列を検索します

server.log ファイルで insertData キーワードを検索します。

    public static void main(String[] args) {
    
            
        String filePath = "D:\\迅雷下载\\server.log";
        String searchWord = "insertData";
        Map<Integer, String> map = SearchWord.scanFile(filePath,searchWord);
        for(Map.Entry<Integer, String> entry : map.entrySet()){
    
    
            System.out.println("第"+entry.getKey()+"行:"+entry.getValue());
        }
     }

出力:

67:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-开始插入数据库list大小:368:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-nowadays:2021-12-27 15:10:4269:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-handleResult结束
第70:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-firm大小:15

7. フォルダー内の指定した種類のファイル内の文字列を検索します。

D:\Xunlei Download\ にあるすべての「txt」、「log」タイプのファイルでキーワード insertData を見つけます。

    public static void main(String[] args) {
    
       
	    String dir = "D:\\迅雷下载\\";
        String searchStr = "insertData";
        List<String> fileType = Arrays.asList("txt", "log");
        Map<String, Map<Integer, String>> map = SearchWord.searchFiles(dir, searchStr, fileType);
        for (Map.Entry<String, Map<Integer, String>> m : map.entrySet()) {
    
    
            System.out.println("文件路径: " + m.getKey());
            for (Map.Entry<Integer, String> n : m.getValue().entrySet()) {
    
    
                System.out.println("第" + n.getKey() + "行:" + n.getValue());
            }
            System.out.println();
        }
    }

または

    public static void main(String[] args) {
    
       
		SearchWord.searchAndPrint(dir,searchStr,fileType);
    }

出力:

文件路径: D:\迅雷下载\server.log
第67:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-开始插入数据库list大小:368:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-nowadays:2021-12-27 15:10:4269:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-handleResult结束
第70:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-firm大小:15
    
文件路径: D:\迅雷下载\新建文件夹\note.txt
第15行:insertData-插入数据库
第17行:insertData-fserviceid:21-1419行:insertData-firmpv:120行:insertData-firmuv:121行:insertData-userpv:122行:insertData-useruv:1

8. 指定したフォルダを除く、フォルダ配下の指定した種類のファイル内の文字列を検索します。

D:\Xunlei Download\ フォルダーにあるすべての「txt」、「log」タイプのファイルでキーワード insertData を検索します。フォルダー名が「新しいフォルダー」の場合は、このフォルダーの検索を除外します。

    public static void main(String[] args) {
    
       
	    String dir = "D:\\迅雷下载\\";
        String searchStr = "insertData";
        List<String> fileType = Arrays.asList("txt", "log");
        List<String> excludeDir = Arrays.asList("新建文件夹"); //遇到文件夹名为"新建文件夹"则跳过该文件夹
        Map<String, Map<Integer, String>> map = SearchWord.searchFiles(dir, searchStr, fileType, excludeDir);
        for (Map.Entry<String, Map<Integer, String>> m : map.entrySet()) {
    
    
            System.out.println("文件路径: " + m.getKey());
            for (Map.Entry<Integer, String> n : m.getValue().entrySet()) {
    
    
                System.out.println("第" + n.getKey() + "行:" + n.getValue());
            }
            System.out.println();
        }
    }

出力:

文件路径: D:\迅雷下载\server.log
第67:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-开始插入数据库list大小:368:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-nowadays:2021-12-27 15:10:4269:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-handleResult结束
第70:[http-nio-8080-exec-339  2021 Dec 27 15:10:42]insertData-firm大小:15

9. 指定したフォルダー内の読み取り可能なすべてのファイル内の文字列を検索します。

D:\Xunlei Download\ フォルダーにあるすべてのテキスト ファイルでキーワード ssssss を検索します。デフォルトでは、音楽やビデオなどの非テキスト ファイルは検索されません

    public static void main(String[] args) throws IOException {
    
    
 		String dir = "D:\\迅雷下载\\";
        String searchStr ="ssssss";
        Map<String, Map<Integer, String>> map = SearchWord.searchAllFiles(dir, searchStr);
        System.out.println("");
        System.out.println("--------------------------------------------------------");
        System.out.println("搜索完成,结果:");
        for (Map.Entry<String, Map<Integer, String>> m : map.entrySet()) {
    
    
            System.out.println("文件路径: " + m.getKey());
            for (Map.Entry<Integer, String> n : m.getValue().entrySet()) {
    
    
                System.out.println("第" + n.getKey() + "行:" + n.getValue());
            }
            System.out.println();
        }
    }

出力:

正在扫描文件夹:D:\迅雷下载\
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1\laydate
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1\laydate\theme
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\font
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1\文档
正在扫描文件夹:D:\迅雷下载\test
正在扫描文件夹:D:\迅雷下载\新建文件夹
正在文件中搜索,当前搜索文件:D:\迅雷下载\aaa
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\font\iconfont.eot
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\font\iconfont.woff
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\laydate.css
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\test.html
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\文档\官网.url


--------------------------------------------------------
搜索完成,结果:
文件路径: D:\迅雷下载\aaa
第1行:ssssss

10. 指定したフォルダーを除く、指定したフォルダー内のすべての読み取り可能なファイル内の文字列を検索します

D:\Xunlei Download\ フォルダーの下の指定されたフォルダーを確認し、すべてのテキスト ファイルでキーワード ssssss を検索します。デフォルトでは、音楽やビデオなどの非テキスト ファイルは検索されません。

    public static void main(String[] args) throws IOException {
    
    
        String dir = "D:\\迅雷下载\\";
        String searchStr ="ssssss";
        List<String> excludeDir = Arrays.asList("laydate"); //遇到文件夹名为laydate"则跳过该文件夹
        Map<String, Map<Integer, String>> map = SearchWord.searchAllFiles(dir, searchStr,excludeDir);
        System.out.println("");
        System.out.println("--------------------------------------------------------");
        System.out.println("搜索完成,结果:");
        for (Map.Entry<String, Map<Integer, String>> m : map.entrySet()) {
    
    
            System.out.println("文件路径: " + m.getKey());
            for (Map.Entry<Integer, String> n : m.getValue().entrySet()) {
    
    
                System.out.println("第" + n.getKey() + "行:" + n.getValue());
            }
            System.out.println();
        }
    }

出力:

正在扫描文件夹:D:\迅雷下载\
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1
正在扫描文件夹:D:\迅雷下载\layDate-v5.3.1\文档
正在扫描文件夹:D:\迅雷下载\test
正在扫描文件夹:D:\迅雷下载\新建文件夹
正在文件中搜索,当前搜索文件:D:\迅雷下载\aaa
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\font\iconfont.eot
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\font\iconfont.woff
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\laydate\theme\default\laydate.css
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\test.html
正在文件中搜索,当前搜索文件:D:\迅雷下载\layDate-v5.3.1\文档\官网.url


--------------------------------------------------------
搜索完成,结果:
文件路径: D:\迅雷下载\aaa
第1行:ssssss

11. 瓶パッケージとして使用する

    public static void main(String[] args) throws IOException {
    
    
        List<String> excludeDir = Arrays.asList("laydate"); //遇到文件夹名为"新建文件夹"则跳过该文件夹
        String dir = ""; //要扫描的文件夹
        String searchStr = ""; //要查找的字符串
        String[] array = null; //不查找的文件夹名
        for (int i = 0; i < args.length; i++) {
    
    
            if (i == 0) {
    
    
                dir = args[i];
            }else if (i == 1) {
    
    
                searchStr = args[i];
            }else if (i == 2) {
    
    
                String tempDirs = args[i];
                array = tempDirs.split(",");
            }
            System.out.println("参数" + (i + 1) + "的值为:" + args[i]);
        }
        Map<String, Map<Integer, String>> map = array == null ? SearchWord.searchAllFiles(dir, searchStr) : SearchWord.searchAllFiles(dir, searchStr, new ArrayList<>(Arrays.asList(array)));
        System.out.println("");
        System.out.println("--------------------------------------------------------");
        System.out.println("搜索完成,结果:");
        for (Map.Entry<String, Map<Integer, String>> m : map.entrySet()) {
    
    
            System.out.println("文件路径: " + m.getKey());
            for (Map.Entry<Integer, String> n : m.getValue().entrySet()) {
    
    
                System.out.println("第" + n.getKey() + "行:" + n.getValue());
            }
            System.out.println();
        }
    }

jar パッケージにパッケージ化すると、サーバー上で使用できるようになります。scan.jar としてパッケージ化されているとすると、コマンドは次のようになります。

java -jar scan.jar param1 param2 param3

このうち、param1はスキャン対象のフォルダ、param2は検索対象の文字列、param3は検索対象外のフォルダ名をカンマ区切りで指定します。

例:
D:\myFiles\ フォルダーの下でファイルを検索し、文字列 love を含む場所を検索し、move または music という名前のフォルダーが見つかった場合はそのフォルダーをスキップします。

java -jar scan.jar D:\myFiles\ love move,music

12. マルチスレッド検索

マルチスレッドを使用して、単純な複数ファイルの検索文字列プログラムを作成することを検討してください。folderPath
、searchStr、containsSubFolder という 3 つのパラメータがあるとします。これらのパラメータはそれぞれ、フォルダ パス、検索する文字列、およびサブディレクトリを検索するかどうかを表します。
containsSubFolder が false の場合は、folderPath フォルダー (そのサブディレクトリを除く) の下にあるすべての読み取り可能なファイルのどの行に searchStr のキー文字列が含まれるかを検索し、その行の内容を出力します。 containsSubFolder が true の場合は、次の内容を含むフォルダーパス フォルダーを検索します。
サブディレクトリ内のすべての読み取り可能なファイルの中で、どの行に searchStr キー文字列が含まれているかを調べ、この行の内容を出力します。

考慮事項:
1. 2 つのスレッドを使用します:
- スレッド A は、フォルダー内のすべての読み取り可能なファイルのパスをスキャンし、キューに入れます。
- スレッド B は、キューからファイル パス データを継続的にフェッチし、ファイル内を検索します
。スレッド B はいつ終了しますか:
- スレッド A がスキャンした後、スレッド A が終了したことを通知するためにスレッド B にフラグを返す必要があります;
- スレッド B がスレッド A が終了したことを認識した場合、スレッド B はデータがあるかどうかを判断する必要がありますキューにない場合は、すべてのファイルが検索されたことを意味し、検索は終了します;
3. スレッド間の通信、つまり共有変数を考慮します
4. A で与えられたデータを格納するためにどのキューを使用するかを検討しますスレッドを作成し、スレッド B にデータを提供します
。 5. 結果は、スレッド A とスレッド B の両方が実行された後にのみ出力されます。

次のコードは、固定長スレッド プールを使用して 2 つのスレッドを作成し、LinkedBlockingQueue 無制限ブロッキング キューを使用してスレッド A からデータを受信し、データをスレッド B に提供します。AtomicBoolean を使用してスレッド間で変数を共有し、CountDownLatch を使用して待機します。結果を出力する前に実行を完了する 2 つのスレッド。

ツール クラス SearchUtils は次のとおりです。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;

public class SearchUtils {
    
    

    //当在文件夹中搜索时,遇到以下常见的非文本文件则跳过
    public static List<String> excludeFileType = Arrays.asList(
            "jar", "zip", "rar", "7z", "tar", "gz", "xz", "bz2", "doc", "class", "pak",
            "xls", "ppt", "pdf", "docx", "xlsx", "pptx", "jpg", "jpge", "gif", "png",
            "xltd", "war", "hprof", "m4a", "swf", "mobi", "jpeg", "tiff", "svg", "psd",
            "mp3", "aac", "mp4", "avi", "flv", "mkv", "mkv", "mpeg", "msi", "tgz",
            "rmvb", "apk", "ts", "map", "car", "mov", "wav", "raw", "dll", "woff",
            "eot", "otf", "ico", "ttf", "ttc", "fon", "dl_", "pd_", "ex_", "etl",
            "sys", "iso", "isz", "esd", "wim", "gho", "dmg", "mpf", "exe", "ldf", "mdf");

    
	/**
     * 获取 folderPath 文件夹下的所有的可读文件的路径,并将 路径存入 allFilesPath 里
     *
     * @param folderPath  要搜索的文件夹路径
     * @param allFilesPath 可读文件的路径存放进allFilesPath
     * @param containsSubFolder 是否搜索子文件夹
     */
    public static void getAllReadFilessPath(String folderPath, BlockingQueue<String> allFilesPath, boolean containsSubFolder) {
    
    
        File file = new File(folderPath);
        File[] tempList = file.listFiles();
        //System.out.println("正在扫描文件夹:" + dirPath);
        if (null == tempList) {
    
    
            return;
        }
        for (int i = 0; i < tempList.length; i++) {
    
    
            String filePath = tempList[i].toString();
            String file_Type = filePath.substring(filePath.lastIndexOf(".") + 1).toLowerCase();;
            if (tempList[i].isFile()) {
    
    
                //如果是文件并且是可读的文本文件
                if (!excludeFileType.contains(file_Type)) {
    
    
                    try {
    
    
                        allFilesPath.put(filePath);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
            } else {
    
    
                //如果是文件夹且要读取子文件夹
                if (containsSubFolder) {
    
    
                    getAllReadFilessPath(filePath, allFilesPath, containsSubFolder);
                }
            }
        }
    }

    
	/**
     * 不断从 allFilesPath 里取文件路径然后搜索文件中是否含有关键字,把结果存到 searchResult 里
     *
     * @param allFilesPath  用于从该队列中获取文件路径
     * @param searchStr 要搜索的关键字
     * @param searchResult 存放最终的结果
     * @param scanFinish 要搜索的关键字
     */
    public static void searchAllFiles(BlockingQueue<String> allFilesPath, String searchStr, Map<String, Map<Integer, String>> searchResult, AtomicBoolean scanFinish) {
    
    
        while (true) {
    
    
            String filePath = null;
            try {
    
    
                filePath = allFilesPath.poll(1, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            //在 filePath 文件中搜索 searchStr 关键字
            Map<Integer, String> map = scanFile(filePath, searchStr);
            if (map.size() != 0) {
    
    
                searchResult.put(filePath, map);
            }
            if (allFilesPath.size() == 0 && scanFinish.get()) {
    
    
                //若队列中的数据已经取完并且扫描线程也已经扫描完就跳出循环
                break;
            }
        }
    }

    /**
     * 搜索指定文件中的关键字
     *
     * @param filePath  要搜索的文件路径
     * @param searchStr 要搜索的关键字
     * @return 返回的 map<行数, 该行内容>
     */
    public static Map<Integer, String> scanFile(String filePath, String searchStr) {
    
    
        Map<Integer, String> map = new LinkedHashMap<>();
        if (filePath == null) {
    
    
            return map;
        }
        FileInputStream file = null; //读取文件为字节流
        try {
    
    
            file = new FileInputStream(filePath);
            InputStreamReader in = new InputStreamReader(file, StandardCharsets.UTF_8); //字节流转化为字符流,以UTF-8读取防止中文乱码
            BufferedReader buf = new BufferedReader(in); //加入到缓存区
            String str = "";
            int row = 1;
            while ((str = buf.readLine()) != null) {
    
     //按行读取,到达最后一行返回null
                if (str.contains(searchStr)) {
    
    
                    map.put(row, str);
                }
                row++;
            }
            buf.close();
            file.close();
        } catch (FileNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return map;
    }
}



マルチスレッドコード:

   public static void main(String[] args) throws Exception {
    
    
		//搜索 F 盘及其子文件夹下所有可读文件中那些文件包含 "g789d" 关键字
        Map<String, Map<Integer, String>> searchResult = search("F:\\", "g789d", true);
        StringBuffer result = new StringBuffer();
        for (Map.Entry<String, Map<Integer, String>> m : searchResult.entrySet()) {
    
    
            result.append("  文件: " + m.getKey());
            result.append("\n");
            for (Map.Entry<Integer, String> n : m.getValue().entrySet()) {
    
    
                result.append("\t第 " + n.getKey() + " 行:" + n.getValue() + "\n");
            }
            result.append("\n\n ");
        }
        System.out.println(result.toString());

    }

    public static Map<String, Map<Integer, String>> search( String folderPath, String searchStr, boolean containsSubFolder){
    
    
        //存储所有的扫描的可读文件的路径
        BlockingQueue<String> allFilesPath = new LinkedBlockingQueue<>();
        //用于判断扫描线程是否已扫描完成
        AtomicBoolean scanFinish = new AtomicBoolean(false);
        //存储所有搜索的结果<文件名,<行数,内容>>
        Map<String, Map<Integer, String>> searchResult = new LinkedHashMap<>();
        //线程计数器
        CountDownLatch countDownLatch = new CountDownLatch(2);

        //创建一个定长线程池,初始化为2
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);

        //创建一个线程用于扫描所有的可读文件路径,然后存放到 allFilesPath 里,扫描完将 scanFinish 设为 true
        fixedThreadPool.execute(() -> {
    
    
            SearchUtils.getAllReadFilessPath(folderPath, allFilesPath, containsSubFolder);
            scanFinish.set(true);//当此线程扫描完所有线程后将scanFinish设置为true
            countDownLatch.countDown();//线程计数器减一
        });

        //创建一个线程不断从 allFilesPath 里取文件路径然后搜索文件中是否含有关键字,把结果存到 searchResult 里,
        // 当 allFilesPath 为空并且 scanFinish 为true (即上面的线程扫描完了,此线程也把 allFilesPath 里的所有的文件扫描完了),就跳出searchAllFiles方法
        fixedThreadPool.execute(() -> {
    
    
            SearchUtils.searchAllFiles(allFilesPath, searchStr, searchResult, scanFinish);
            countDownLatch.countDown();
        });

        try {
    
    
            //等待上面两个线程执行完
            countDownLatch.await();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        //关闭线程池
        fixedThreadPool.shutdown();
        return searchResult;
    }

結果:

  文件: F:\asposeHtml\aa_files\we.txt
	第 4 行:fhfg789dfrh

   文件: F:\fileTypeTest\havaAttachFile\we.txt
	第 4 行:fhfg789dfrh

   文件: F:\spireHtml\myExcel_files\we.txt
	第 4 行:fhfg789dfrh

   文件: F:\we.txt
	第 4 行:fhfg789dfrh
	第 8 行:fhfg789dfrh
	第 12 行:fhfg789dfrh

   文件: F:\ydz\test\新建文件夹\we.txt
	第 4 行:fhfg789dfrh

この例は単純なプロデューサーとコンシューマーの問題であり、プロデューサーとコンシューマーは 1 つだけです。プロデューサーとコンシューマーが複数ある場合は、次を参照できます。

Java スレッドでの BlockingQueue を使用したプロデューサー コンシューマー ソリューション
Java での例によるプロデューサーとコンシューマーの問題

おすすめ

転載: blog.csdn.net/qq_33697094/article/details/122237127