欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaFX 项目实战 —— 文件内容搜索软件 (二)

程序员文章站 2024-01-20 18:40:46
...

需要先完成上一节的代码:https://blog.csdn.net/qq_40515692/article/details/104602531

演示:

通过``符号与英语查询相区分。-r表示查询的根目录,-c表示查询的文件内容,-e表示文件后缀(无-e表示全部搜索)
JavaFX 项目实战 —— 文件内容搜索软件 (二)

自己刚学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);
    }
}

有问题欢迎留言评论!