【Java】一个类搞定代码行统计

数月前在一个项目,听见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

原文地址:https://www.cnblogs.com/heyang78/p/15754885.html