目录
前言
如果你想扫描某一目录下(包含子目录下)有哪些文件;或者你想搜索某个文件夹下所有文件的内容,哪些文件的哪一行包含关键字 “xxx”,那么这篇文章可以帮到你。
一、工具类
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", "gzip", "gz", "xz", "bz2", "doc", "class", "pak", "webm", "appx",
"xls", "ppt", "pdf", "ofd", "docx", "xlsx", "pptx", "jpg", "jpge", "gif", "png", "ett", "ram",
"xltd", "war", "hprof", "m4a", "swf", "mobi", "jpeg", "tif", "tiff", "svg", "psd", "eps", "qsv",
"mp3", "aac", "mp4", "avi", "flv", "mkv", "mpeg", "msi", "tgz", "mdf", "xlsm", "rm", "ogg", "mod",
"rmvb", "apk", "ts", "map", "car", "mov", "wav", "raw", "dll", "woff", "igs", "dwt", "dng", "msix",
"eot", "otf", "ico", "ttf", "ttc", "fon", "dl_", "pd_", "ex_", "etl", "dwf", "iges", "wpt", "cer",
"sys", "iso", "isz", "esd", "wim", "gho", "dmg", "mpf", "exe", "ldf", "mpg", "3dm", "fbx", "bin",
"wmv", "3gp", "drawio", "dcm", "tga", "bmp", "jfif", "webp", "dwg", "dxf", "vsd", "vsdx", "api",
"ifc", "dwfx", "stl", "cf2", "plt", "obj", "3ds", "stl", "ply", "gltf", "glb", "off", "et", "mpp",
"dae", "wrl", "3mf", "ifc", "brep", "step", "iges", "fcstd", "bim", "epub", "wmf", "emf", "CHS",
"xmind", "odt", "ods", "ots", "odp", "otp", "six", "ott", "fodt", "fods", "wps", "dps", "x3d");
/**
* 搜索指定文件中的关键字
*
* @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;
}
/**
* @param dirPath 要搜索的文件夹路径
* @param fileNamelist 要搜索的文件名列表
* @return 返回要查找的文件的路径
*/
public static List<String> getFilesPath(String dirPath, List<String> fileNamelist) {
return getFilesPath(dirPath, fileNamelist, new ArrayList<>(), false);
}
/**
* @param dirPath 要搜索的文件夹路径
* @param fileName 要搜索的文件名
* @return 返回要查找的文件的路径(即使不同文件夹有多个一样的文件,只返回找到的第一个)
*/
public static String getFilesPath(String dirPath, String fileName) {
List<String> filesPath = getFilesPath(dirPath, Collections.singletonList(fileName), new ArrayList<>(), true);
return filesPath.size() == 0 ? "" : filesPath.get(0);
}
//遍历文件夹下所有的文件,根据 fileNamelist 中的文件名 ,获取文件的文件路径
private static List<String> getFilesPath(String dirPath, List<String> fileNamelist, List<String> list, boolean justQueryFirst) {
File file = new File(dirPath);
File[] tempList = file.listFiles();
if (null != tempList) {
for (int i = 0; i < tempList.length; i++) {
String filePath = tempList[i].toString();
if (tempList[i].isFile()) {
String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
if (null != fileNamelist && fileNamelist.contains(fileName)) {
list.add(filePath);
}
if (justQueryFirst && list.size() == 1) {
return list;
}
} else {
if (justQueryFirst && list.size() == 1) {
return list;
}
//如果是文件夹则递归
getFilesPath(filePath, fileNamelist, list, justQueryFirst);
}
}
}
return list;
}
}
二、扫描文件夹下所有文件
扫描D:\迅雷下载\文件夹下的所有文件
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
三、扫描文件夹下所有文件,排除指定文件夹
扫描D:\迅雷下载\文件夹下的所有文件,不扫描"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
四、扫描文件夹下指定类型文件
扫描D:\迅雷下载\文件夹下是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
五、扫描文件夹下指定类型文件,排除指定文件夹
扫描D:\迅雷下载\文件夹下是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
六、在指定文件中搜索字符串
在 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大小:3
第68行:[http-nio-8080-exec-339 2021 Dec 27 15:10:42]insertData-nowadays:2021-12-27 15:10:42
第69行:[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:\迅雷下载\ 下所有 “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大小:3
第68行:[http-nio-8080-exec-339 2021 Dec 27 15:10:42]insertData-nowadays:2021-12-27 15:10:42
第69行:[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-14
第19行:insertData-firmpv:1
第20行:insertData-firmuv:1
第21行:insertData-userpv:1
第22行:insertData-useruv:1
八、在文件夹下指定类型的文件中搜索字符串,排除指定文件夹
在 D:\迅雷下载\ 文件夹下所有 “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大小:3
第68行:[http-nio-8080-exec-339 2021 Dec 27 15:10:42]insertData-nowadays:2021-12-27 15:10:42
第69行:[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:\迅雷下载\ 文件夹下所有文本文件中查找关键字 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
十、在指定文件夹下的所有可读文件中搜索字符串,排除指定文件夹
在 D:\迅雷下载\ 文件夹下排查指定文件夹,然后在所有文本文件中查找关键字 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
十一、根据文件名查找文件路径
1.寻找多个文件名
public static void main(String[] args) throws IOException {
//要查找的文件夹路径
String dir = "D:\\GoogleDown\\";
//查找文件名叫 guava-30.1.1-jre.jar 、 former.html 、xelem.xml 的文件,然后返回文件的路径
List<String> filesName = Arrays.asList("guava-30.1.1-jre.jar", "former.html", "xelem.xml");
//开始查找
List<String> filesPath = SearchWord .getFilesPath(dir, filesName);
filesPath.forEach(System.out::println);
}
输出:
D:\GoogleDown\former.html
D:\GoogleDown\guava-30.1.1-jre.jar
D:\GoogleDown\xelem-3.1\xelem-3.1\config\xelem.xml
D:\GoogleDown\xelem-3.1\xelem-3.1\examples\config\xelem.xml
2.寻找单个文件名
public static void main(String[] args) throws IOException {
//要查找的文件夹路径
String dir = "D:\\GoogleDown\\";
//查找文件名叫 xelem.xml 的文件,然后返回文件的路径。(即使不同文件夹有多个相同文件,找到第一个就立即返回,剩下的就不再继续找)
String filesName = "xelem.xml";
//开始查找
String filesPath = SearchWord .getFilesPath(dir, filesName);
System.out.println(filesPath);
输出:
D:\GoogleDown\xelem-3.1\xelem-3.1\config\xelem.xml
十二、打成jar包使用
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
十三、多线程搜索
考虑用多线程做个简单的多文件搜索字符串的程序:
假设有三个参数folderPath、searchStr、containsSubFolder ,其分别代表文件夹路径、要搜索的字符串、是否搜索子目录。
如果 containsSubFolder 为 false 就只搜索 folderPath 文件夹下(不包含其子目录)所有可读文件中哪几行包含 searchStr 关键字符串,并输出该行内容;
如果 containsSubFolder 为 true 就搜索 folderPath 文件夹下包含其子目录的所有可读文件中哪几行包含 searchStr 关键字符串,并输出该行内容。
需要考虑的点:
1.采用2个线程:
- 线程 A 扫描文件夹下所有的可读文件的路径然后放到队列里;
- 线程 B 去不断从队列里取文件路径数据然后去文件中搜索;
2. 线程 B 何时结束:
- 线程 A 扫描结束后,应该返回一个标识给线程 B 告诉它 A 线程已经结束了;
- 当 B 线程得知 A 线程结束后 B 线程要判断队列里还有没有数据,没有的话说明全部的文件都搜索完了,就结束搜索;
3.考虑线程间的通信,即共享变量
4.考虑使用使用什么队列来存放 A 线程给的数据,以及给 B 线程提供数据
5.考虑只有A、B两个线程都执行完后才输出结果。
下面的代码将使用定长线程池创建两个线程,然后使用 LinkedBlockingQueue 无界阻塞队列接收 A 线程数据以及为 B 线程提供数据,使用 AtomicBoolean 来线程间共享变量,使用CountDownLatch来等待两个线程执行完再输出结果。
工具类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
本例只是一个简单的生产者和消费者问题,且生产者和消费者都只有一个,如果有多个生产者和消费者可以参考:
Producer Consumer Solution using BlockingQueue in Java Thread
Producer-Consumer Problem With Example in Java