java代码实现-统计代码的小工具-base版

在检查项目的代码时,就想想有没有可以统计代码行数的小工具类。就上度娘查,专业的感觉比较麻烦,代码写的还是找到了。

Java统计代码的小工具

看了他的代码,并且考下来跑了一下,挺好的,能用。

但是只能统计java代码,就在想能不能统计别的语言的代码呢?经过几个版本的代码修改,中间的代码太烂就不放出来了,嘿嘿。

最终代码,自己感觉比开始的好点了,就是多线程暂时没考虑,如果后期有时间就试着弄一下吧。也可能后期会忘了,Σ( ° △ °|||)︴。

中间java菜单处理类没接触过,就在网上找了点资料,附上参考的文章路径:

JFileChooser 文件选择对话框API

java文件对话框的使用(包括文件多选,文件、文件夹同时可选操作)

现在的代码如下。

主程序:

package utils;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;

/**
 * 代码扫描分析小工具
 * 
 * @author WinSonZhao()
 * @version v1.0
 * @Date 2018年9月5日 上午8:40:40
 * @Create eclipse Mars.2 Release (4.5.2)
 * @source https://www.aliyun.com/jiaocheng/330673.html
 * @source https://blog.csdn.net/maozhennba3/article/details/50359857
 * @source https://www.cnblogs.com/ning1121/p/3738065.html?utm_source=tuicool&utm_medium=referral
 */
public class CodeCounterFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	/**用于制作菜单栏时用到的一个组件
	 */
	JMenuBar menuBar = new JMenuBar();
	/**菜单-给窗口添加菜单条
	 */
	JMenu fileMenu = new JMenu("文件");
	/**菜单项-打开一个文件
	 */
	JMenuItem openMenuItem = new JMenuItem("打开");
	JMenuItem openMenuFileItem = new JMenuItem("打开指定目录");
	JMenuItem cleanItem = new JMenuItem("清空");
	JMenuItem openMenuItems = new JMenuItem("打开多个");
	/**文本域-编辑多行的文本(\r\n 换行)(\t 制表符)
	 */
	JTextArea txa = new JTextArea();
	/**视图容器
	 */
	JScrollPane jsp = new JScrollPane(txa);
	/**记录输出的字符串
	 */
	protected StringBuffer out=new StringBuffer("");
	public CodeCounterFrame() {
		this.setJMenuBar(this.menuBar);
		//添加菜单条
		this.menuBar.add(fileMenu);
		//添加菜单项
		this.fileMenu.add(this.openMenuItem);
		this.fileMenu.add(this.cleanItem);
		this.fileMenu.add(this.openMenuFileItem);
		this.fileMenu.add(this.openMenuItems);
		// txa里面的内容不能被编辑
		this.txa.setEditable(false); 
		add(this.jsp);
		// 内部匿名类监听器
		this.openMenuItem.addActionListener(new ActionListener() {
			// 点击了打开菜单
			public void actionPerformed(ActionEvent e) {
				if (e.getSource() == openMenuItem) {
					init_1(null);
				}
			}
		});
		this.cleanItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(e.getSource() == cleanItem){
					txa.setText("");
                    clear();
				}
			}
		});
		this.openMenuFileItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(e.getSource() == openMenuFileItem){
					init_1("D:\\0Working\\workspace\\");
				}
			}
		});
		this.openMenuItems.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(e.getSource() == openMenuItems){//指定目录
					init_2("D:\\0Working\\");
				}
			}
		});
	}
	/**
	 * 清空
	 * @param br
	 */
	public void clear() {
		if (this.out != null && this.out.length() > 0) {
			// 清空
			this.out.delete(0, out.length() - 1);
		}
	}
	public void init_2(String fName){
		JFileChooser chooser = new JFileChooser();// 弹出文件选择器
		if(fName!=null&&!"".equals(fName.trim())){
			chooser.setCurrentDirectory(new File(fName));//打开指定目录
		}
		//设置文件选择器,以允许选择多个文件
		chooser.setMultiSelectionEnabled(true);
		//弹出一个带标题的 "Open File" 文件选择器对话框
		chooser.showOpenDialog(null);
		//可以选择文件和目录
//		chooser.setFileSelectionMode(chooser.FILES_AND_DIRECTORIES);
		// 获取选中的文件
		File[] selectedFiles = chooser.getSelectedFiles();
		if(selectedFiles==null||selectedFiles.length<=0){
			txa.setText("使用‘打开多个’菜单,未选择文件");
			return;
		}
		CodeFacetory cf=new CodeFacetory();
		for(File f:selectedFiles){
			out.append(cf.scanFile(f));
		}
		txa.setText(out.toString());
	}
	//选择‘打开’菜单,选择一个文件
	public void init_1(String fName){
		JFileChooser chooser = new JFileChooser();
		if(fName!=null&&!"".equals(fName.trim())){
			chooser.setCurrentDirectory(new File(fName));
			//弹出一个带标题的 "Open File" 文件选择器对话框
			chooser.showDialog(null,"指定目录");
		}else{
			//弹出一个 "Open File" 文件选择器对话框
			//等同于:showOpenDialog(null)
			chooser.showDialog(null,"默认目录");
		}
		// 获取选中的文件
		File selectedFile = chooser.getSelectedFile();
		if(selectedFile==null){
			txa.setText("使用‘打开’菜单,未选择文件");
			return;
		}
		CodeFacetory cf=new CodeFacetory();
		out.append(cf.scanFile(selectedFile));
		txa.setText(out.toString());
	}
	
	// Frame主程序
	public static void main(String[] args) {
		try {// windows界面风格
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
		} catch (Exception e) {
			e.printStackTrace();
		}
		CodeCounterFrame frame = new CodeCounterFrame();
		frame.setTitle("统计代码的小工具");
		frame.setSize(600, 400);
		frame.setVisible(true);
		frame.setLocationRelativeTo(null);// 窗体居中显示
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
}

根据文件类型处理的工厂类

package utils;

import java.io.BufferedReader;
import java.io.File;

/**
 * 处理文件工厂类
 * @author WinSonZhao()
 * @version v1.0
 * @Date 2018年9月5日 下午5:45:59
 * @Create eclipse Mars.2 Release (4.5.2)
 */
public class CodeFacetory {
	public String scanFile(File... file){
		BufferedReader br = null;
		CodeFace cf=null;
		if(file==null||file.length<=0){
			return "未选择文件";
		}
		String name="";
		StringBuilder sb=new StringBuilder("");
		for(File f:file){
			name=f.getName();
			if(name.endsWith(".java")){
				cf=new CodeJava();
			}else if(name.endsWith(".xml")){
				cf=new CodeXml();
			}else{
				return name+"【文件格式不能解析】\r\n";
			}
			cf.start(f,br);
			sb.append(name).append("\t");
			sb.append(cf.to_StringBuilder()).append("\r\n");
		}
		return sb.toString();
	}
}

定义的接口,方便工厂类中使用

package utils;

import java.io.BufferedReader;
import java.io.File;

/**
 * 接口
 * @author WinSonZhao()
 * @version v1.0
 * @Date 2018年9月5日 下午5:19:08
 * @Create eclipse Mars.2 Release (4.5.2)
 */
public interface CodeFace {
	/**
	 * 工具入口
	 * @param file
	 * @param br
	 * @return
	 */
	public void start(File file,BufferedReader br);
	/**
	 * 组装统计文本
	 * @return
	 */
	public String to_String();
	/**
	 * 组装统计文本
	 * @return
	 */
	public StringBuilder to_StringBuilder();
	/**
	 * 清空
	 * @param br
	 */
	public void clear();
}

定义的特定格式文件解析父类(名称暂时就叫这个吧,起名真费劲……)

package utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * 代码扫描父类
 * 
 * @author WinSonZhao()
 * @version v1.0
 * @Date 2018年9月6日 上午8:51:16
 * @Create eclipse Mars.2 Release (4.5.2)
 * @see 当前版本,只是考虑功能实现,暂时没考虑多线程并发的共享资源的问题,后期有时间再弄吧(也可能是无期)
 */
public class CodeCounter implements CodeFace {
	/**
	 * 记录输出的字符串
	 */
	protected StringBuilder out = new StringBuilder("");
	/**
	 * 装载从缓存中读取的数据
	 */
	protected String line = "";
	/**
	 * 缓存区-装载读文件的缓存
	 */
	protected BufferedReader br = null;
	/**
	 * 代码行数
	 */
	protected static long codeLines = 0;
	/**
	 * 注释行数
	 */
	protected static long commentLines = 0;
	/**
	 * 空白行数
	 */
	protected static long blankLines = 0;

	public CodeCounter() {
		clear();// 清空
	}

	public CodeCounter init(BufferedReader br) {
		this.br = br;
		return this;
	}

	public CodeCounter init(StringBuilder out) {
		this.out = out;
		return this;
	}

	/**
	 * 工具入口
	 * 
	 * @param file
	 * @param br
	 * @return
	 */
	public void start(File file, BufferedReader br) {
		if (this.out == null) {
			this.out = new StringBuilder();
		}
		try {
			this.buffer(file, br);
		} catch (FileNotFoundException ex) {
			throw new CodeException("File Is Not Found...."+file);
		} catch (IOException ex) {
			throw new CodeException("BufferedReader Io Exception...."+br);
		} catch (Exception ex) {
			throw new CodeException(ex);
		} finally {
			this.close(br);
		}
	}

	/**
	 * 清空
	 * 
	 * @param br
	 */
	public void clear() {
		if (this.out != null && this.out.length() > 0) {
			// 清空
			this.out.delete(0, out.length() - 1);
		}
	}

	/**
	 * 工具入口
	 * 
	 * @param file
	 * @param br
	 * @return
	 * @throws IOException 
	 */
	protected void buffer(File file, BufferedReader br) throws IOException {
		// 读取文档的内容
		FileReader reader = new FileReader(file);
		// 读文件,缓存区
		br = new BufferedReader(reader);
		String name = file.getName();
		out.append(name).append("\t");
		this.scan(br);
		clear();// 清空
	}

	/**
	 * 核心代码-扫描java文件内容,统计代码
	 * 
	 * @param br
	 * @throws IOException
	 */
	protected void scan(BufferedReader br) throws IOException {
		boolean comment = false;
		// 文件内容提取,按行读取
		while ((line = br.readLine()) != null) {
			// 除去注释前的空格
			line = line.trim(); 
			if (line.matches("^[ ]*$")) {
				blankLines++;// 匹配空行
			} else if (line.startsWith("//")) {
				commentLines++;// 单行注释
			} else if (line.startsWith("/*") && line.endsWith("*/")) {
				commentLines++;// 多行注释,只有一行的情况
			} else if (line.startsWith("/*") && !line.endsWith("*/")) {
				commentLines++;// 多行注释,开始
				comment = true;
			} else if (comment == true) {
				commentLines++;
				// 多行注释,结束
				if (line.endsWith("*/")) {
					comment = false;
				}
			} else {// 其他的都算为有效代码
				codeLines++;
			}
		}
	}

	/**
	 * 关闭缓存,并清空
	 * 
	 * @param br
	 */
	protected void close(BufferedReader br) {
		if (br != null) {
			try {
				br.close();
				br = null;
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}

	/**
	 * 统计总行数
	 * 
	 * @return
	 */
	public long sum() {
		return codeLines + commentLines + blankLines;
	}

	/**
	 * 组装基础的统计数据
	 */
	protected void to() {
		out.append("代码行数:").append(codeLines).append("\t");
		out.append("注释行数:").append(commentLines).append("\t");
		out.append("空白行数:").append(blankLines).append("\t");
	}

	/**
	 * 组装统计文本
	 * 
	 * @return
	 */
	public String to_String() {
		to();
		out.append("总行数:").append(sum());
		return out.toString();
	}

	/**
	 * 组装统计文本
	 * 
	 * @return
	 */
	public StringBuilder to_StringBuilder() {
		to();
		out.append("总行数:").append(sum());
		return out;
	}
}

java文件的处理,这个是将父类完全覆盖,可以按需要定制解析

package utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * 统计java文件的类
 * @author WinSonZhao()
 * @version v1.0
 * @Date 2018年9月5日 下午4:33:59
 * @Create eclipse Mars.2 Release (4.5.2)
 */
public class CodeJava  extends CodeCounter implements CodeFace{
	/**记录输出的字符串
	 */
	protected StringBuilder out=new StringBuilder("");
	/**装载从缓存中读取的数据
	 */
	protected String line = "";
	/**缓存区-装载读文件的缓存
	 */
	protected BufferedReader br=null;
	/**代码行数
	 */
	static long codeLines = 0;
	/**注释行数
	 */
	static long commentLines = 0;
	/**空白行数
	 */
	static long blankLines = 0;
	public CodeJava(){
		clear();
	}
	public CodeJava init(BufferedReader br){
		this.br=br;
		return this;
	}
	public CodeJava init(StringBuilder out){
		this.out=out;
		return this;
	}
	public String to_String() {
		to();
		out.append("总行数:").append(sum());
		return out.toString();
	}
	public StringBuilder to_StringBuilder() {
		to();
		out.append("总行数:").append(sum());
		return out;
	}
	public void start(File file, BufferedReader br) {
		if (this.out == null) {
			this.out = new StringBuilder();
		}
		try {
			this.buffer(file, br);
		} catch (FileNotFoundException ex) {
			throw new CodeException("File Is Not Found...."+file);
		} catch (IOException ex) {
			throw new CodeException("BufferedReader Io Exception...."+br);
		} catch (Exception ex) {
			throw new CodeException(ex);
		} finally {
			this.close(br);
		}
	}
	protected void to(){
		out.append("代码行数:").append(codeLines).append("\t");
		out.append("注释行数:").append(commentLines).append("\t");
		out.append("空白行数:").append(blankLines).append("\t");
	}
	/**
	 * 清空
	 */
	public void clear() {
		if(this.out!=null&&this.out.length()>0){
			this.out.delete(0, out.length()-1);//清空
		}
	}
	/**
	 * 统计总行数
	 */
	public long sum(){
		return codeLines + commentLines + blankLines;
	}
	/**
	 * 工具入口
	 */
	protected void buffer(File file,BufferedReader br) throws IOException{
		FileReader reader = new FileReader(file);// 读取文档的内容
		br = new BufferedReader(reader);//读文件,缓存区
		String name=file.getName();
		out.append(name).append("\t");
		this.scan(br);//
		this.clear();//清空
	}
	/**
	 * 核心代码-扫描java文件内容,统计代码
	 */
	protected void scan(BufferedReader br) throws IOException{
		boolean comment = false;
		while ((line = br.readLine()) != null) {// 文件内容提取,按行读取
			line = line.trim(); // 除去注释前的空格
			if (line.matches("^[ ]*$")) {
				blankLines++;// 匹配空行
			} else if (line.startsWith("//")) {
				commentLines++;//单行注释
			} else if (line.startsWith("/*") && line.endsWith("*/")) {
				commentLines++;//多行注释,只有一行的情况
			} else if (line.startsWith("/*") && !line.endsWith("*/")) {
				commentLines++;//多行注释,开始
				comment = true;
			} else if (comment == true) {
				commentLines++;
				if (line.endsWith("*/")) {//多行注释,结束
					comment = false;
				}
			} else {//其他的都算为有效代码
				codeLines++;
			}
		}
	}
	/**
	 * 关闭缓存,并清空
	 * @param br
	 */
	protected void close(BufferedReader br){
		if (br != null) {
			try {
				br.close();
				br = null;
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}
}

xml文件解析,如果只是核心代码分析不一样,可以很简单实现

package utils;

import java.io.BufferedReader;
import java.io.IOException;

/**
 * @author WinSonZhao()
 * @version v1.0
 * @Date 2018年9月5日 下午5:18:41
 * @Create eclipse Mars.2 Release (4.5.2)
 */
public class CodeXml extends CodeCounter implements CodeFace{
	protected void scan(BufferedReader br) throws IOException{
		boolean comment = false;
		while ((line = br.readLine()) != null) {// 文件内容提取,按行读取
			line = line.trim(); // 除去注释前的空格
			if (line.matches("^[ ]*$")) {
				blankLines++;// 匹配空行
			} else if (line.startsWith("<!--") && line.endsWith("-->")) {
				commentLines++;//多行注释,只有一行的情况
			} else if (line.startsWith("<!--") && !line.endsWith("-->")) {
				commentLines++;//多行注释,开始
				comment = true;
			} else if (comment == true) {
				commentLines++;
				if (line.endsWith("-->")) {//多行注释,结束
					comment = false;
				}
			} else {//其他的都算为有效代码
				codeLines++;
			}
		}
	}
}

发布后,发现没有异常类,补上,虽然也没啥。测试统计中,分析了这类,可以数一下,o(∩_∩)o 哈哈

package utils;

/**
 * 自定义异常
 * @author WinSonZhao(***)
 * @version v1.0
 * @Date 2018年9月6日 上午9:16:43
 * @Create eclipse Mars.2 Release (4.5.2)
 */
public class CodeException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	//构造
	public CodeException() {
		super("CodeException:Something is really wrong! hi hi..");
	}
	/*构造*/
	public CodeException(String message) {
        super("CodeException:"+message);
    }
	/*构
	 * 造*/
	public CodeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}
	public CodeException(String message, Throwable cause) {
		super(message, cause);
	}
	public CodeException(Throwable cause) {
		super(cause);
	}
}

下面就是一些截图了

默认打开的路径
菜单截不了屏,只能用手机了,Σ( ° △ °|||)︴
选择多个文件的分析结果

配置文件就不上传了

我还扩展了jsp和js 的分析,就不传了,jsp就做了简单的统计,没有做细致的分析。

因为这个代码只写了一天,中间改了好多次。还是比较简陋,望各位大佬多多指教呀,小弟在此谢过啦……

就这样吧,( ^_^ )/~~拜拜

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值