JavaFX 项目实战 —— 文件内容搜索软件 (二)
程序员文章站
2024-01-20 18:40:46
...
需要先完成上一节的代码:https://blog.csdn.net/qq_40515692/article/details/104602531
演示:
通过``符号与英语查询相区分。-r表示查询的根目录,-c表示查询的文件内容,-e表示文件后缀(无-e表示全部搜索)
自己刚学JavaFx,有问题欢迎指出讨论!希望帮到了大家!
一、命令行解析和根目录文件获取
java有专门的命令行解析库,但是我直接用的正则表达式解析,虽然很难看,但是还阔以,输入的是输入框的字符串,输出的是解析得到的String数组,正则表达式学得不好,不知道怎么简化写法了。
public static String[] readLineSearch(String str) {
Pattern pc = Pattern.compile("-c=(?<q>.*?)[`\\s]");
Pattern pe = Pattern.compile("-e=(?<q>.*?)[`\\s]");
Pattern pr = Pattern.compile("-r=(?<q>.*?)[`\\s]");
Matcher mc = pc.matcher(str);
Matcher me = pe.matcher(str);
Matcher mr = pr.matcher(str);
String[] res = new String[3];
if (me.find()) res[0] = me.group("q");
if (mc.find()) res[1] = mc.group("q");
if (mr.find()) res[2] = mr.group("q");
return res;
}
根目录文件获取,用递归的方式把所有结果保存到 listFileName
public static void getAllFileName(String path, ArrayList<String> listFileName) {
File file = new File(path);
File[] files = file.listFiles();
String[] names = file.list();
if (names != null) {
String[] completNames = new String[names.length];
for (int i = 0; i < names.length; i++)
completNames[i] = path + names[i];
listFileName.addAll(Arrays.asList(completNames));
}
if (files != null)
for (File f : files)
if (f.isDirectory())
getAllFileName(f.getAbsolutePath() + "\\", listFileName);
}
二、筛选文件
根据三个参数的值,筛选文件。并加入一些信息。
public static List<String> searchFileContent(String rootPath, String end, String content) {
List<String> res = new ArrayList<>();
ArrayList<String> listFileName = new ArrayList<>();
getAllFileName(rootPath, listFileName);
res.add("该路径下共有文件数:" + listFileName.size());
ArrayList<String> listFileName2 = new ArrayList<>();
if (end == null || end.equals("")) {
listFileName2 = listFileName;
} else {
String[] rail = end.split("!");
for (String name : listFileName)
for (String item : rail)
if (name.contains(item)) { // 用的contains,所以不一定是后缀
listFileName2.add(name);
break;
}
listFileName.clear(); // 用完了,及时(ノ`Д)ノ java是引用,所以上面的条件还是不要滚
}
res.add("该路径下后缀满足共有文件数:" + listFileName2.size());
if (content == null || content.equals("")) { // 表示不查找文件内容
res.add("---查找成功---");
res.addAll(listFileName2);
return res;
}
ArrayList<String> listFileName3 = new ArrayList<>();
for (String name : listFileName2) {
StringBuilder stringBuilder = new StringBuilder(); // 大文件读取会爆栈
try {
FileReader fileReader = new FileReader(name);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = bufferedReader.readLine();
while (line != null) {
line = bufferedReader.readLine();
stringBuilder.append(line);
}
bufferedReader.close();
fileReader.close();
} catch (Exception e) { // 什么文件无法访问呢,文件太大呀,直接continue
res.add(e.toString());
continue;
}
if (stringBuilder.toString().contains(content))
listFileName3.add(name);
}
if (listFileName3.size() > 0) {
res.add("---查找成功---");
res.add("该路径下后缀满足且内容满足共有文件数:" + listFileName3.size());
res.addAll(listFileName3);
} else {
res.add("---未发现该内容文件---");
}
return res;
}
三、整合功能
上面三个函数已经把功能大致弄好了,剩下的就是去Main文件下面,整合这些功能。修改输入框的事件响应如下:
input.textProperty().addListener((observable, oldValue, newValue) -> {
String trimed = newValue.trim();
if (trimed.length() <= 0) {
primaryStage.setHeight(80);
return;
}
if (trimed.charAt(0) == '`') {
// 后面的`相当于回车
if (trimed.length() == 1 || trimed.charAt(trimed.length() - 1) != '`') {
primaryStage.setHeight(80);
return;
}
// 文件查找 格式举例 `-r=C:\Users\ttp\Desktop -c=你好 -e=.txt!.cpp` `-r=F: -e=txt -c=hello` `-r=F: -c=hello` 可能爆栈
String[] res = readLineSearch(trimed);
if (res[2].charAt(res[2].length() - 1) != '\\') res[2] += "\\"; // 添加\
// 文件查找线程开启,总不能让GUI卡死吧
new Thread(() -> {
try {
listview.getItems().clear();
listview.getItems().add("正在查找");
List<String> searchResult = searchFileContent(res[2], res[0], res[1]);
listview.getItems().clear();
listview.getItems().add("查找完成");
listview.getItems().addAll(searchResult);
} catch (Exception e1) {
listview.getItems().clear();
listview.getItems().add(e1.toString());
e1.printStackTrace();
}
}).start();
} else {
// 单词查找
List<String> searchResult = Word.search(trimed, word.words, String::contains);
listview.getItems().clear();
listview.getItems().addAll(searchResult);
}
primaryStage.setHeight(400);
});
四、双击朗读和双击复制
得到路径后自然需要双击复制(不可能用手打吧),随便把上一节的一个坑双击朗读给实现了。这里直接给出Main文件:
public class Main extends Application {
private Word word = new Word();
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Demo");
primaryStage.setScene(new Scene(root));
primaryStage.setHeight(80);
primaryStage.setResizable(false);//窗口不可改变高度 宽度 这样就不用调节自适应了
primaryStage.setOpacity(0.8);//设置透明度 0为完全透明 1为完全不透明 默认是1
primaryStage.initStyle(StageStyle.UNDECORATED);//设定窗口无边框
primaryStage.show();
// 一定show();完再lookup
TextField input = (TextField) root.lookup("#input");
ListView<String> listview = (ListView<String>) root.lookup("#listView");
input.textProperty().addListener((observable, oldValue, newValue) -> {
String trimed = newValue.trim();
if (trimed.length() <= 0) {
primaryStage.setHeight(80);
return;
}
if (trimed.charAt(0) == '`') {
// 后面的`相当于回车
if (trimed.length() <= 3 || trimed.charAt(trimed.length() - 1) != '`') {
primaryStage.setHeight(80);
return;
}
// 文件查找 格式举例 `-r=C:\Users\ttp\Desktop -c=你好 -e=.txt!.cpp` `-r=F: -e=txt -c=hello` `-r=F: -c=hello` 可能爆栈
String[] res = readLineSearch(trimed);
if (res[2].charAt(res[2].length() - 1) != '\\') res[2] += "\\"; // 添加\
// 文件查找线程开启,总不能让GUI卡死吧
new Thread(() -> {
try {
listview.getItems().clear();
listview.getItems().add("正在查找");
List<String> searchResult = searchFileContent(res[2], res[0], res[1]);
listview.getItems().clear();
listview.getItems().add("查找完成");
listview.getItems().addAll(searchResult);
ChangeListener<Object> changeListener = new ChangeListener<Object>() {
@Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
// 获取系统剪贴板,是awt包下的
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable trans = new StringSelection((String) newValue);
clipboard.setContents(trans, null);
listview.getSelectionModel().selectedItemProperty().removeListener(this);
}
};
listview.getSelectionModel().selectedItemProperty().addListener(changeListener);
} catch (Exception e1) {
listview.getItems().clear();
listview.getItems().add(e1.toString());
e1.printStackTrace();
}
}).start();
} else {
// 单词查找
List<String> searchResult = Word.search(trimed, word.words, String::contains);
listview.getItems().clear();
listview.getItems().addAll(searchResult);
// 朗读
ChangeListener<Object> changeListener = new ChangeListener<Object>() {
@Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue == null) return;
String str = (String) newValue;
String res = str.split("\\s+")[0];
AudioClip audioClip = new AudioClip("http://dict.youdao.com/dictvoice?audio=" + res);
audioClip.play();
listview.getSelectionModel().selectedItemProperty().removeListener(this);
}
};
listview.getSelectionModel().selectedItemProperty().addListener(changeListener);
}
primaryStage.setHeight(400);
});
}
public static void main(String[] args) {
launch(args);
}
}
有问题欢迎留言评论!