通过关键词检索目录下的所有日志文件,然后返回搜索的内容,这个工具用于定位日志特别有用;搜索服务的类通过多线程,每一个线程搜索一个文件,效率很高,上百个文件基本上都是在几秒内完成。
搜索服务的源码:
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);
}
}
现在来看一下效果:


