通过关键词检索目录下的所有日志文件,然后返回搜索的内容,这个工具用于定位日志特别有用;搜索服务的类通过多线程,每一个线程搜索一个文件,效率很高,上百个文件基本上都是在几秒内完成。
搜索服务的源码:
package system.service; import system.service.base.BaseService; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; public class TextFindService extends BaseService implements Runnable { private String path; private String name; private String[] keywords; private List<String> result = new ArrayList<>(); private boolean working; public TextFindService(String path, String name, String[] keywords) { this.path = path; this.name = name; this.keywords = keywords; this.working = true; } @Override public void run() { File file = new File(getPath() + getName()); InputStreamReader reader = null; BufferedReader br = null; long time = System.currentTimeMillis(); if (!file.exists()) { this.putLog(getName() + ":文件不存在"); return; } this.putLog(getName() + ":开始搜索..."); try { reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8); br = new BufferedReader(reader); String line = null; int count = 0; while ((line = br.readLine()) != null) { if (!working) { Thread.yield(); break; } boolean find = true; for (String kds : getKeywords()) { if (!line.toLowerCase().contains(kds.toLowerCase())) { find = false; break; } } if (find) { getResult().add(line); count++; } } this.putLog(getName() + ":完毕,找到" + count + "行数据"); } catch (IOException e) { e.printStackTrace(); this.putLog(e.getMessage()); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } working = false; } this.putLog(getName() + ":搜索结束...use time " + (System.currentTimeMillis() - time) + "ms"); } private String getPath() { return path; } private String[] getKeywords() { return keywords; } public List<String> getResult() { return result; } public String getName() { return name; } public void stop() { this.working = false; } private void putLog(String data) { this.getResult().add(data); log(data); } public static void main(String[] args) { String path = "C:\\Users\\Downloads\\test\\"; String name = "my.log"; String keywords = "keywords"; TextFindService find = new TextFindService(path, name, keywords.split(";")); find.run(); for (String str : find.getResult()) { System.out.println(str); } } public boolean isDone() { return !working; } }
这里面比较重要的就是run()函数中的源码,复杂搜索、工作状态判断、让权等;完成之后还不忘关闭文件句柄。
其中服务类main()主函数是我用来测试使用的,但这只能在源码里调试,添加一个GUI界面会更方便。
新增一个java swing GUI图形界面,这个工具更加遍历,不用每次都编写代码去检索。
Swing编程源代码:
package view; import system.component.Button; import system.component.TextEdit; import system.component.TextView; import system.conf.Constant; import system.lib.CompactController; import system.lib.IController; import system.service.TextFindService; import system.utils.DateTimeUtils; import system.utils.StringUtils; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.io.*; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class LogSplitViewController extends CompactController implements IController, ActionListener, FocusListener { private TextEdit path, keywords; private JTextArea logs; private TextView labPath, labKey, labLogs, status; private Button start, stop; private static final String TIP_PATH = "Input the logs directory path."; private static final String TIP_KEYWORDS = "Multi keywords use ';' of symbol to split."; private List<TextFindService> findServiceList = new ArrayList<>(); private String version = "20210903#v1.0"; public LogSplitViewController() { super(680, 500); } @Override protected void createInit() { int x = 10, y = 10; path = new TextEdit(); keywords = new TextEdit(); logs = new JTextArea(); path.setName("path"); keywords.setName("keywords"); labPath = new TextView("Directory:"); labKey = new TextView("Keywords:"); labLogs = new TextView("Logs:"); status = new TextView("finished."); start = new Button("Analyse"); stop = new Button("Break"); labPath.setBounds(x, y, 80, 28); labKey.setBounds(x, y + 38, 80, 28); labLogs.setBounds(x, y + 76, 80, 28); path.setBounds(x + 65, y, 450, 32); keywords.setBounds(x + 65, y + 38, 450, 32); status.setBounds(0, y + 432, 680, 30); status.setBackground(Color.BLACK); status.setForeground(Color.green); JScrollPane scrollPane1 = new JScrollPane(logs); scrollPane1.setBounds(x + 40, y + 42 * 2, 600, 335); logs.setForeground(Color.green); logs.setBackground(Color.BLACK); start.setBounds(x + 530, y, 100, 32); stop.setBounds(x + 530, y + 38, 100, 32); this.setLayout(null); this.add(start); this.add(stop); this.add(path); this.add(keywords); this.add(status); this.add(scrollPane1); this.add(labLogs); this.add(labPath); this.add(labKey); start.addActionListener(this); stop.addActionListener(this); this.setTip(keywords, TIP_KEYWORDS); this.setTip(path, TIP_PATH); stop.setEnabled(false); } @Override public void init() { } @Override public void showX() { this.setTitle(Constant.TITLE_LOG_SPLIT + " - " + version); this.setResizable(false); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); this.init(); } @Override public void close() { } @Override public void hideX() { } private String[] keys() { String string = keywords.getText(); if (string.contains(";")) { return string.split(";"); } if (string.contains("|")) { return string.split("|"); } return string.split(";"); } private void initFind() { start.setEnabled(false); stop.setEnabled(true); } private void lastFind() { start.setEnabled(true); stop.setEnabled(false); } private void find() { try { initFind(); checkFind(); findBefore(); File file = new File(path.getText()); if (!file.exists()) { throw new Exception("The directory is don't exists."); } this.doFind(file.getPath() + "/", file.listFiles()); } catch (Exception e) { e.printStackTrace(); } finally { // lastFind(); } } private void doFind(String path, File[] listFiles) { long time = System.currentTimeMillis(); logPut("开始查找...path=" + path); String logname = DateTimeUtils.format(DateTimeUtils.getLocalDateTime(), "yyyyMMddHHmmss") + ".log"; for (File file : listFiles) { logPut(" - 创建查找服务 " + file.getName()); TextFindService service = new TextFindService(path, file.getName(), keys()); findServiceList.add(service); new Thread(service).start(); } new Thread(() -> { while (true) { if (System.currentTimeMillis() - time > 3600000) { logPut("超时,放弃查找..."); break; } Iterator<TextFindService> iterator = findServiceList.iterator(); if (!iterator.hasNext()) { break; } while (iterator.hasNext()) { TextFindService service = iterator.next(); if (service.isDone()) { iterator.remove(); this.write(path, logname, service.getResult(), service.getName()); } } } logPut("查找完成!用时:" + (System.currentTimeMillis() - time) + "ms"); lastFind(); }).start(); } private synchronized void write(String path, String logname, List<String> result, String name) { logPut(name + " 文件查找完成,写入到文件:" + logname); File file = new File(path + logname); FileOutputStream out = null; try { out = new FileOutputStream(file, true); out.write(("--------------------------" + name + "------------------------------").getBytes()); out.write("\n".getBytes()); for (String s : result) { out.write(s.getBytes()); out.write("\n".getBytes()); } out.flush(); } catch (IOException e) { e.printStackTrace(); logPut(e.getMessage()); } finally { if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } logPut("写入文件完成"); logPut("还剩:" + findServiceList.size() + "个文件"); } } private void breakFind() { logPut("breaking..."); for (TextFindService service : findServiceList) { service.stop(); } logPut("breaking done."); lastFind(); } private void findBefore() { logs.setText(""); findServiceList.clear(); } private void checkFind() throws Exception { if (StringUtils.isEmptyTrim(path.getText()) || TIP_PATH.equals(path.getText())) { dialog(TIP_PATH); throw new Exception(TIP_PATH); } if (StringUtils.isEmptyTrim(keywords.getText()) || TIP_KEYWORDS.equals(keywords.getText())) { dialog("least one keyword"); throw new Exception("least one keyword"); } } private void setTip(TextEdit keywords, String tipKeywords) { if (!StringUtils.isEmptyTrim(keywords.getText())) { return; } keywords.setForeground(Color.gray); keywords.setText(tipKeywords); keywords.addFocusListener(this); } @Override public void actionPerformed(ActionEvent e) { Button button = (Button) e.getSource(); if ("Analyse".equals(button.getName())) { find(); } else if ("Break".equals(button.getName())) { breakFind(); } } @Override public void focusGained(FocusEvent e) { TextEdit obj = ((TextEdit) (e.getSource())); if (TIP_KEYWORDS.equals(obj.getText())) { obj.setForeground(Color.black); obj.setText(""); } else if (TIP_PATH.equals(obj.getText())) { obj.setForeground(Color.black); obj.setText(""); } } @Override public void focusLost(FocusEvent e) { TextEdit obj = ((TextEdit) (e.getSource())); if ("path".equals(obj.getName()) && obj.getText().length() == 0) { setTip(obj, TIP_PATH); } else if ("keywords".equals(obj.getName()) && obj.getText().length() == 0) { setTip(obj, TIP_KEYWORDS); } } private void logPut(String msg) { logs.setText(logs.getText() + LocalDateTime.now().toString() + " " + msg + "\n"); logs.setCaretPosition(logs.getDocument().getLength()); status.setText(msg); } }
现在来看一下效果: