一个简单的代码计数器的实现

时间:2021-07-30 03:41:42

source counter

这是一个简单的懒人源码统计工具.目前实现的功能相对来说比较简单,只是对注释,空白行和代码做了简单的区分.
之后还想加入一些更精确的统计方式.不过,暂时还没想好要怎么弄.(捂脸,逃…)

目前的源码已经上传至github,下载的话请点击这里. sourceCounter

下面简单介绍一下实现

查找一个目录及其子目录下的文件

这个很简单,一个递归就搞定了. 第一个方法getAllFiles() 是查找一个目录及其子目录下的所有文件.
第二个方法是根据指定的文件名查找文件.文件名在这里都是使用字符串来记录的. 所以,完全可以使用正则表达式来匹配所有后缀为*.java的文件. 当然,也可以匹配其他后缀的文件.

1.public class FileUtils {
2.
3. private static List<String> fileList = new ArrayList<String>();
4.
5.
6. /**
7. * to get all files in a directory and it's child dir
8. * @param root
9. * @return
10. */

11. private static void getAllFiles(String root){
12. File[] files = new File(root).listFiles();
13. for(File eachFile : files){
14. if(eachFile.isDirectory()){
15. FileUtils.getAllFiles(eachFile.getAbsolutePath());
16. // fileList.add(eachFile.getAbsolutePath());
17. }else {
18. fileList.add(eachFile.getAbsolutePath());
19. }
20.
21. }
22. }
23.
24. public static List<String> findFiles(String root,String type){
25. getAllFiles(root);
26. List<String> sourceFile =new ArrayList<String>();
27. Pattern pattern = Pattern.compile("\\."+type+"$");
28. for(String eachFile:fileList){
29. Matcher matcher = pattern.matcher(eachFile);
30. if(matcher.find()){
31. sourceFile.add(eachFile);
32. }
33.
34. }
35. return sourceFile;
36. }
37.}

区分源码中的代码行,空行和注释行

这里核心就是一个正则表达式的匹配. 需要注意的两个地方是:

  • 转义字符: 比如,对于”//”这个来说, 它对于java的正则引擎而言它是保留关键字,是需要转义的. 转义的方式很简单,按照正常的剧本应该是在字符前加上”\”就可以了.(话说这是正斜杠还是反斜杠啊,分不清…),所以”//”的转义应该是”\/\/”. 但是!!!but!!! java里对于”\” 也特么被保留了. 所以如果想表示”//” 应该写成”\/\/” . 或者使用unicode编码来进行转义. 我翻遍我当年的笔记,关于正则表达式中的转义字符全写的是”\”而不是”\”… 自己把自己坑了…
  • 关于空行:java源码里的空行大部分都是由于排版需要敲出来的空格,换行符和制表符.(貌似空行也就这三类吧…). 所以匹配空行的正则表达式是\\s*|\t|\r|\n"
1.public class CounterUtils {
2. /**
3. * match each line in a source file to distinguish source code and comments
4. * @param sourceFile
5. * @return
6. * @throws IOException
7. */

8. public static Map<String, Integer> sourceFileCounter(File sourceFile) throws IOException{
9. int sourceCount =0;
10. int commentCount=0;
11. Map<String, Integer> counterMap = new HashMap<String, Integer>();
12.
13. FileReader fr = new FileReader(sourceFile);
14. BufferedReader br = new BufferedReader(fr);
15.
16. Pattern singleCommentPattern = Pattern.compile("\\/\\/"); //single line comments
17. Pattern blockCommentPattern1 = Pattern.compile("\\/\\*");//block comments
18. Pattern blockCommentPattern2 = Pattern.compile("\\*");//block comments
19. Pattern blankPattern = Pattern.compile("\\s*|\t|\r|\n");//blank line
20.
21. String eachLine = null;
22.
23. while((eachLine=br.readLine())!=null){
24. Matcher singleCommentMatcher = singleCommentPattern.matcher(eachLine);
25. Matcher blockComment1Matcher = blockCommentPattern1.matcher(eachLine);
26. Matcher blockComment2Matcher = blockCommentPattern2.matcher(eachLine);
27. Matcher blankMatcher = blankPattern.matcher(eachLine);
28. if(singleCommentMatcher.find()||blockComment1Matcher.find()||blockComment2Matcher.find()){
29. commentCount++;
30. }else if (blankMatcher.matches()) {
31. continue;
32. }else {
33. sourceCount++;
34. }
35. }
36.
37. counterMap.put("sourceCount", sourceCount);
38. counterMap.put("commentCount",commentCount);
39.
40. return counterMap;
41. }
42.}

操作excel的第三方jar包

由于以前写的工具,绝大部分都是处理文本数据用的. 所以我对正则表达式和excel,csv文件情有独钟. 按照我的设想是,程序运行之后,将统计数据记录到excel中,方便我日后画图. 所以这里使用了一个第三方的jar包来操作保存结果的excel.

这里使用的是jexcelapi. 还挺方便的,api一看就懂.

可能是我的脑回路不正常,按照我的理解,这个jar包并没有提供直接修改一个excel的方法. 因为它所有workbook相关的方法都叫createXXX. 但是后来看到一个例子,可以先get到你需要修改的excel文件,然后再create的时候作为copy传进去. 先在读取原文件,然后操作,然后覆盖回写. 反正也达到了修改的目的.

1.public class ExcelUtils {
2. public static void writeToResultFile(int sourcCount,int commentsCount,String path)
3. throws IOException, BiffException, RowsExceededException, WriteException
{
4. String sourceCount = Integer.toString(sourcCount);
5. String commentCount = Integer.toString(commentsCount);
6.
7. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
8. String date=sdf.format(new Date());
9.
10.
11. File resultFile = new File(path);
12. //get source workbook
13. Workbook book = Workbook.getWorkbook(resultFile);
14. //create a new workbook using source workbook as a copy
15. WritableWorkbook wb = Workbook.createWorkbook(resultFile, book);
16. WritableSheet sheet = wb.getSheet(0);
17. int rows = sheet.getRows();
18.
19. if(rows==0){
20. //add a cell
21. Label dateLabel = new Label(0,0,"date");
22. Label srcLabel = new Label(1,0,"srcCount");
23. Label cmtLabel = new Label(2,0,"cmtCount");
24.
25. sheet.addCell(cmtLabel);
26. sheet.addCell(srcLabel);
27. sheet.addCell(dateLabel);
28. rows++;
29. }
30. Label dateLabel = new Label(0,rows,date);
31. Label srcCount = new Label(1,rows,sourceCount);
32. Label cmtCount = new Label(2,rows,commentCount);
33.
34. sheet.addCell(dateLabel);
35. sheet.addCell(srcCount);
36. sheet.addCell(cmtCount);
37.
38. wb.write();
39. wb.close();
40.
41. }
42.}

统计一个目录下的所有指定类型源文件

好了,文件查找的方法有了,源码内容识别的方法有了,回写记录的方法也有了. 我们最后要做的就是把这些玩意儿整合起来,让它可以工作.

我平时使用myeclipse和eclipse,所以源码基本上都在一个目录下面, 而且,到目前为止,我只关心java代码的数量(因为我只会这玩意儿…) 但是显然,这个玩意儿除了java代码还可以查找其他类型的源码. 所以我不想把它写的太死板,留了一个配置文件出来. 需要的时候可以直接修改配置文件就可以了.

1.path=C\:\\Users\\thecatcher\\Documents\\workbench
2.fileType=java
3.resultPath=C\:\\Users\\thecatcher\\Documents\\codeCounter.xls

主方法很简单,就是把这些玩意儿穿起来.

1.public class SourceCounter {
2. private static String path;
3. private static String fileType;
4. private static String resultFile;
5. private static Map<String, Integer> sourceCounterMap = new HashMap<String, Integer>();
6.
7. public static void main(String[] args) throws FileNotFoundException,
8. IOException, RowsExceededException, BiffException, WriteException
{
9. //get configuration info form config file
10. Properties prop = new Properties();
11. prop.load(new FileInputStream(
12. new File(
13. "C:\\Users\\thecatcher\\Documents\\workbench\\SourceCounter\\src\\config.properties")));
14.
15. path = prop.getProperty("path");
16. fileType = prop.getProperty("fileType");
17. resultFile = prop.getProperty("resultPath");
18.
19. List<String> sourceFileList = FileUtils.findFiles(path, fileType);
20.
21. //initialize data map
22. sourceCounterMap.put("sourceCount", 0);
23. sourceCounterMap.put("commentCount", 0);
24.
25. for (String eachFile : sourceFileList) {
26. Map<String, Integer> eachFileMap = CounterUtils
27. .sourceFileCounter(new File(eachFile));
28. sumCounter(eachFileMap, sourceCounterMap, "sourceCount");
29. sumCounter(eachFileMap, sourceCounterMap, "commentCount");
30. }
31. // System.out.println(sourceCounterMap.get("sourceCount"));
32. // System.out.println(sourceCounterMap.get("commentCount"));
33. // System.out.println(sourceFileList.size());
34. ExcelUtils.writeToResultFile(sourceCounterMap.get("sourceCount"),
35. sourceCounterMap.get("commentCount"), resultFile);
36.
37. System.out.println("---------------------");
38. System.out.println("done!");
39. System.out.println("---------------------");
40. System.out.println("source Code: "+sourceCounterMap.get("sourceCount"));
41. System.out.println("commentCount: "+sourceCounterMap.get("commentCount"));
42. }
43.
44. private static void sumCounter(Map<String, Integer> srcMap,
45. Map<String, Integer> destMap, String key)
{
46. int srcCounter = srcMap.get(key);
47. int destCounter = destMap.get(key);
48. int sum = srcCounter + destCounter;
49.
50. destMap.put(key, sum);
51. }
52.
53.}

将工程打包成可执行的jar包

表示这个还真是用百度google到的内容. 之前一直写写写,却没有想过怎么打包工程…
首先说一件很羞耻的事情…我用的破解版的myeclipse10…为啥用这个,因为最初启蒙入门的时候看别人的教学视频,人家用的就是这个,所以一直就用下来了. 我想我会改邪归正…不再用盗版软件的…

步骤很简单,

在项目上右键,export,然后选择runnable JAR file

一个简单的代码计数器的实现

然后,第一个选择你的程序主类入口,第二个选择导出位置

 一个简单的代码计数器的实现
下面那个是选择如何处理添加的第三方类库的.不重要,我就保持了默认的第一个.

然后点finish就可以了.

重点来了

这么个小玩意儿很好写,但是写完之后怎么用呢? 我最初的想法是能每天定时执行,然后等我足够牛X的时候,拿出来画个图看看自己代码量增长的曲线,顺带缅怀一下逝去的青春(捂脸,再逃…)

每天手动点一次,这个方法太low了. 毕竟,我是个连呼吸都觉得略累的懒宅死胖子. 考虑到我严重的失眠情况以及几乎趋近于0的夜生活,我的电脑,几乎每天凌晨00:00都是处于运行状态的. 所以我定了一个定时任务. 让这个玩意儿每天零点都执行一下.

首先写一个批处理,很简单,一句话:

1.@echo off
2.java -jar C:\Users\thecatcher\Documents\002.tools\sourceCounter\counter.jar
3.pause

然后,开始菜单里找到任务计划程序–操作–创建基本任务

一个简单的代码计数器的实现

名称描述随便写了.

一个简单的代码计数器的实现

然后下一步,触发器,看你要执行的频率和条件.

然后操作,这里我们选启动程序

一个简单的代码计数器的实现

然后这里我们找到刚才写的那个批处理文件

一个简单的代码计数器的实现

然后下一步,完成就好了.

要查看刚才新建的计划任务,
在左侧区域选择任务计划程序库就可以看到所有计划任务的执行情况了.

一个简单的代码计数器的实现

我刚刚突然想到一个问题…貌似可以直接根据文件的创建日期或者最后修改日期来统计,这样的话只需要在我想看的时候,执行一下就可以了…我是不是白忙活了…