Java相关技术 - 文件内容检索工具
拿到一个几百M甚至上G的project让你去学习
有时候你会想知道某个关键词是在哪个文件里
比如:spring MVC配置的@RequestMapping,你从页面源知道了Action是 index/login.sftl
然后你想知道,这个@RequestMapping到底是配置在哪个Java类里,你怎么找到这个类呢
又比如,你想知道你当前看到的页面的源文件到底在项目的哪个路径下,你又要什么寻找
别告诉我,你会把项目里的文件一个个打开,直到找到你要的文件
如果每次都这么寻找你要的文件,那...
所以,下面的工具,应运而生了
直接上界面图 (博客界面宽度不够,图片被自动缩放了,可右键图片另存为桌面看,效果会好N多)
看看执行结果图
整个工具就一个类。如果想方便的使用,可以做成自解压文件(.exe),如下图
怎么制作自解压文件?
1.在桌面建一个文件夹: FileChecker
2.在FileChecker文件夹里再建一个文件夹:ace (ace是FileChecker.java所在的package)
3.将FileChecker.java放进上面的文件夹ace里
4.cmd下编译上面的java文件
比如我的:
a. cd C:\Users\Administrator\Desktop\FileChecker\ace
b. javac -sourcepath . -encoding utf-8 FileChecker.java (成功后,ace里会生成多个.class文件)
c. cd.. (返回上一级目录)
d. java -classpath . ace.FileChecker (执行class文件,看看效果)
看到界面后,就可以往下走了
5. 制作自解压文件
a. 写一个批处理文件,用来执行上面的class文件,很简单
(1)在FileChecker目录下新建一个txt文件,然后改名为 start.bat
(2)编辑方式打开start.bat
(3)在里面写上 java -classpath . ace.FileChecker
(4)保存
(5)双击运行start.bat (看到界面就OK了)
做到这一步,后面的也可以不用做了。可以把FileChecker整个文件夹移动到任何地方,然后在桌面创建start.bat的快捷方式,通过快捷方式运行即可
b. 自解压文件的后续步骤
这个相当简单,百度一下,分分钟搞定
代码:
package ace; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.Random; import java.util.Timer; import java.util.TimerTask; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.WindowConstants; import javax.swing.filechooser.FileSystemView; /** * 文件内容检索工具 * * @author liaolongjun 2015年5月30日 下午2:39:07 */ final class FileChecker { private FileChecker() { init(); initFm(); initBtns(); initTextFileds(); initFileChooser(); initCheckBoxPanel(); initSeachLimitPanel(); initFileSelectPanel(); initOutputArea(); initListener(); add(checkBoxPanel, java, html, xml, jsp, js, css, isbreak, all); add(seachLimitPanel, checkBoxPanel, tfSearchContent); add(fileSelectPanel, btnSelect, tfFilePath, btnOK, btnClear, isAutoClear); add(fm, seachLimitPanel, fileSelectPanel, scrollPane); fm.setVisible(true); fm.validate(); } private void init() { try { // 设置为当前操作系统的皮肤 String lookAndFeel = UIManager.getSystemLookAndFeelClassName(); UIManager.setLookAndFeel(lookAndFeel); } catch (Exception e) { outputException(e); } // 读取历史记录 URL url = FileChecker.class.getResource("history.properties");// 如果没有,则在当前class目录下创建 historyFile = url == null ? new File(FileChecker.class.getResource("").getPath() + "/history.properties") : new File(url.getPath()); props = new Properties(); try { props.load(new FileInputStream(historyFile)); filePath = props.getProperty(HISTORY_SEARCH_PATH); searchContent = props.getProperty(HISTORY_SEARCH_CONTENT); } catch (Exception e) { outputException(e); } } private void initFm() { fm = new JFrame("FILE CONTENT CHECKER . liaolongjun . ^(o o)^") { private static final long serialVersionUID = 1L; protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) saveHistory(); // 关闭窗口前,先保存上一次的查询记录 super.processWindowEvent(e); } }; fm.setLayout(null); fm.setSize(1000, 700); fm.setResizable(false); fm.setLocationRelativeTo(null); fm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); Random ran = new Random(); // 每次打开时, 背景色都是随机的 fm.getContentPane().setBackground(new Color(ran.nextInt(255), ran.nextInt(255), ran.nextInt(255))); } private void initOutputArea() { outputArea = new JTextArea(); outputArea.setAutoscrolls(true); // JTextArea 要放在 JScrollPane 里才有滚动效果(同JTable) scrollPane = new JScrollPane(outputArea); scrollPane.setBounds(7, 100, 980, 565); } private void initFileSelectPanel() { fileSelectPanel = new JPanel(); fileSelectPanel.setBounds(7, 55, 980, 40); fileSelectPanel.setBackground(Color.white); } private void initSeachLimitPanel() { seachLimitPanel = new JPanel(); seachLimitPanel.setBounds(7, 5, 980, 45); seachLimitPanel.setBackground(Color.white); } /** * 文件类型过滤(.suffix) */ private void initCheckBoxPanel() { java = new JCheckBox("java", true); html = new JCheckBox("html", true); xml = new JCheckBox("xml"); jsp = new JCheckBox("jsp", true); js = new JCheckBox("js"); css = new JCheckBox("css"); isbreak = new JCheckBox("isbreak", true); // 匹配到一个后是否跳出当前文件 isAutoClear = new JCheckBox("AUTOCLEAR", true); // 自动清除 all = new JCheckBox("all");// 全选 checkBoxPanel = new JPanel(); suffixs = new ArrayList<JCheckBox>(); fillSuffixs(java, html, xml, jsp, js, css); } private void fillSuffixs(JCheckBox... cbs) { for (JCheckBox cb : cbs) suffixs.add(cb); } private void initTextFileds() { // 文件路径 tfFilePath = new JTextField(filePath); tfFilePath.setPreferredSize(new Dimension(560, 30)); // 搜索内容 tfSearchContent = new JTextField(searchContent); tfSearchContent.setPreferredSize(new Dimension(540, 30)); } private void initFileChooser() { // 文件选择器设置桌面默认路径 fc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory()); // 设置只能选择文件夹 fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); } private void initBtns() { btnSelect = new MyBtn("OPEN....."); btnOK = new MyBtn("OK"); btnClear = new MyBtn("CLEAR"); } private void initListener() { btnSelect.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (fc.showOpenDialog(fm) == JFileChooser.APPROVE_OPTION) tfFilePath.setText(fc.getSelectedFile().toString()); } }); btnOK.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 点确定后,重置查询限制条件 resetLimitation(); if (filePath == null || filePath.trim().length() == 0) JOptionPane.showMessageDialog(fm, "未指定路径"); else if (searchContent == null || searchContent.trim().length() == 0) JOptionPane.showMessageDialog(fm, "未指定查询内容"); else check(new File(filePath)); } }); btnClear.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { outputArea.setText(""); } }); all.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setAllSelected(all.isSelected(), suffixs); } }); } /** * 重置查询的限制条件 */ private void resetLimitation() { exts = getExts(); isBreak = isbreak.isSelected(); filePath = tfFilePath.getText(); searchContent = tfSearchContent.getText(); } /** * 获取要限制查找范围的文件后缀名(文件扩展名) */ private List<String> getExts() { List<String> exts = new ArrayList<String>(); for (JCheckBox cb : suffixs) if (cb.isSelected()) exts.add(cb.getText()); return exts.size() > 0 ? exts : null; // 如果没有文件限制,返回null } /** * 是否全选 */ private void setAllSelected(boolean boo, List<JCheckBox> cbs) { for (JCheckBox cb : cbs) cb.setSelected(boo); isbreak.setSelected(boo); // isbreak不在suffixs里, 所以在这里单独设置上 } /** * 添加组件 */ private void add(Container parent, JComponent... components) { for (JComponent c : components) parent.add(c); } /** * 保存查询痕迹 */ private void saveHistory() { try { props.setProperty(HISTORY_SEARCH_PATH, filePath == null ? "" : filePath); props.setProperty(HISTORY_SEARCH_CONTENT, searchContent == null ? "" : searchContent); props.store(new FileOutputStream(historyFile), "--no comment--"); } catch (IOException e) { e.printStackTrace(); } } /** * 打印异常信息 */ private void outputException(Exception e) { outputArea.append(e + "\n"); for (StackTraceElement s : e.getStackTrace()) outputArea.append(" " + s + "\n"); } /** * 检索的文件数目 */ private int numFiles; /** * 满足查询条件的数目 */ private int numResults; private void check(final File file) { if (isAutoClear.isSelected()) btnClear.doClick(); outputArea.append("文件检索中......\n\n"); numFiles = 0; numResults = 0; new Timer().schedule(new TimerTask() { public void run() { try { if (exts == null) check1(file); else check2(file); outputArea.append("\n*\n* 执行结束,一共检索了 " + numFiles + " 个文件。 符合条件:" + numResults + "\n*\n"); outputArea.append("\nHISTORY:" + historyFile + "\n\n"); } catch (Exception e) { outputException(e); } JScrollBar jscrollBar = scrollPane.getVerticalScrollBar(); jscrollBar.setValue(jscrollBar.getMaximum()); } }, 50); } /** * 没有文件类型限制 */ private void check1(File file) throws IOException { File[] files = file.listFiles(); for (File f : files) if (f.isFile()) read(f); else check1(f); } /** * 有文件类型限制 */ private void check2(File file) throws IOException { File[] files = file.listFiles(); for (File f : files) if (f.isFile()) { String ext = getExt(f); if (ext != null && exts.contains(ext)) read(f); } else check2(f); } /** * 获取文件后缀(文件扩展名) */ private String getExt(File file) { String fileName = file.getName(); return fileName.lastIndexOf(".") == -1 ? null : fileName.substring(fileName.lastIndexOf(".") + 1); } private void read(File file) throws IOException { numFiles++; FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); String str; int rowNum = 0; // 行号 if (isBreak) while ((str = br.readLine()) != null) { rowNum++; if (str.indexOf(searchContent) != -1) { numResults++; outputArea.append(file.toString() + "\n" + " 行号: " + rowNum + " " + str + "\n"); break; } } else { StringBuilder sb = new StringBuilder(file.toString() + "\n"); boolean flag = false; while ((str = br.readLine()) != null) { rowNum++; if (str.indexOf(searchContent) != -1) { flag = true; sb.append(" 行号: " + rowNum + " " + str + "\n"); } } if (flag) { numResults++; outputArea.append(sb.toString()); } } br.close(); } /** * 订制规格一致的按钮 */ private class MyBtn extends JButton { private static final long serialVersionUID = 1L; public MyBtn(String btnName) { super(btnName); setPreferredSize(new Dimension(100, 30)); } } /** * 保存上一次查询痕迹的文件 */ private File historyFile; private Properties props; private String filePath; private String searchContent; private final String HISTORY_SEARCH_PATH = "historySearchPath"; private final String HISTORY_SEARCH_CONTENT = "historySearchContent"; private List<JCheckBox> suffixs; private List<String> exts; private boolean isBreak; /** * JFileChooser 文件选择组件 */ private JFileChooser fc; /** * 文件类型 */ private JCheckBox java, html, xml, jsp, js, css, isbreak, all, isAutoClear; /** * 内容输出区域 */ private JTextArea outputArea; private JScrollPane scrollPane; private JFrame fm; private JButton btnSelect, btnOK, btnClear; private JTextField tfSearchContent, tfFilePath; private JPanel checkBoxPanel, seachLimitPanel, fileSelectPanel; public static void main(String[] args) { new FileChecker(); } }
补充一句:运行时,会在ace文件夹里生成一个history.properties文件,用于保存最后一次的检索痕迹。下次运行的时候,会自动显示你上次查询的痕迹(不是查询的结果)
打完,收工!