数月前在一个项目,听见PM说那谁谁用某某工具把代码行统计一下给我,当时作为旁观者的我听了想,这个自己写个类不好吗?
昨天正好一项目也要统计代码行,于是便写了这么一个类:
package test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; /** * 代码行计数器 * 一个类实现工程中各种代码行统计 * @author ufo * 2022年1月1日 */ public class CodelineFigurer { // 要统计的工程根目录 private String root; // 要排除的路径 private List<String> exclusivePaths; // 要排除的扩展名 private List<String> exclusiveExts; // 存储代码文件路径 private List<String> codeFiles; /** * 构造函数 * @param root */ public CodelineFigurer(String root) { this.root=root; } /** * 添加排除路径 * @param path * @return */ public CodelineFigurer addExclusion(String path) { if(exclusivePaths==null) { exclusivePaths=new ArrayList<>(); } exclusivePaths.add(path); return this; } /** * 添加排除扩展名 * @param ext */ public void addExclusiveExt(String ext) { if(exclusiveExts==null) { exclusiveExts=new ArrayList<>(); } exclusiveExts.add(ext); } /** * 开始遍历目录,分类汇总,打印报告 */ public void start() { codeFiles=new ArrayList<>(); tranversal(new File(this.root)); figure(); } /** * 递归遍历目录 * @param folder */ private void tranversal(File folder) { // 遇到排除路径则退出 String path=folder.getAbsolutePath(); for(String exclusivePath:exclusivePaths) { if(path.startsWith(exclusivePath)) { return; } } File[] files=folder.listFiles(); for(File f:files) { if(f.isFile()) { // 遇到排除的扩展名即退出 for(String ext:exclusiveExts) { if(f.getAbsolutePath().endsWith(ext)) { return; } } codeFiles.add(f.getAbsolutePath()); }else if(f.isDirectory()) { tranversal(f); } } } /** * 分类汇总代码行 */ private void figure() { Map<String,Integer> map=new TreeMap<>(); for(String path:codeFiles) { int cnt=countCodeLine(path); if(cnt>0) { String ext=extractExt(path); if(map.containsKey(ext)) { int sum=map.get(ext); sum+=cnt; map.put(ext, sum); }else { map.put(ext, cnt); } } } StringBuilder sb=new StringBuilder(); String line=null; int total=0; for(Entry<String,Integer> entry:map.entrySet()) { int cnt=entry.getValue(); line=String.format("%-10s:%10d\n", entry.getKey(),cnt); sb.append(line); total+=cnt; } line=String.format("%-10s:%10d\n", "total",total); sb.append(line); System.out.println(sb.toString()); } /** * 从文件路径中抽取扩展名 * @param filepath * @return */ private String extractExt(String filepath) { filepath=filepath.toLowerCase(); int dotIdx=filepath.lastIndexOf("."); if(dotIdx>0) { return filepath.substring(dotIdx+1); } return null; } /** * 数一个文本文件中有多少代码行 * 代码行即有文字的行 注释行被认定是代码行的一部分 * @param filepath * @return */ private int countCodeLine(String filepath) { try { int cnt=0; BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(new File(filepath)))); String line=null; while((line=reader.readLine())!=null) { if(line.trim().length()>0) { cnt++; } } return cnt; }catch(Exception ex) { ex.printStackTrace(); return 0; } } // 启动 public static void main(String[] args) { CodelineFigurer cf=new CodelineFigurer("C:\\hy\\prog\\mediaCool\\src"); cf.addExclusion("C:\\hy\\prog\\mediaCool\\src\\main\\resources\\static\\lib").addExclusion("C:\\hy\\prog\\mediaCool\\src\\main\\resources\\static\\stylesheets"); cf.addExclusion("C:\\hy\\prog\\mediaCool\\src\\main\\resources\\static\\images"); cf.addExclusiveExt("gitignore"); cf.start(); } }
输出:
html : 3066 java : 1011 sql : 50 xml : 58 yml : 44 total : 4229
看吧,的确是一个类能搞定!作为程序员,能自己动手编码搞定的事情当然不会求助于工具,您说对吗?
END