代碼量統計工具源碼

源碼說明:
- VALID_SUFFIX_SET可定製,默認只統計.java源碼;
- EXCLUDE_DIRECTORY_SET可定製,默認過濾路徑包含src/test或者target目錄;
- FILTER_COMMENT可定製,默認過濾註釋行
- main()方法中projectNameList包含要統計源碼工程名集合,可定製;默認統計C:\ProjectCode目錄下指定工程源碼,可定製。

package com.afei.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 統計某個文件, 或者某個目錄及其子目錄下所有文件代碼總行數<br/>
 * 例如統計dubbo源碼代碼量
 * @author afei
 * @version 1.0.0
 * @since 2018年04月25日
 */
public class CodeLineCount {

    /**
     * 只統計這個集合約定的文件名後綴的代碼量, 其他後綴全部視爲無效文件 -- it up to you
     */
    private static final Set<String> VALID_SUFFIX_SET = new HashSet<>();
    static {
        VALID_SUFFIX_SET.add(".c");
        VALID_SUFFIX_SET.add(".h");
        //.java文件爲需要統計代碼的文件
        VALID_SUFFIX_SET.add(".java");
        //.xml文件爲需要統計代碼的文件
        // VALID_SUFFIX_SET.add(".xml");
        //.properties文件爲需要統計代碼的文件
        // VALID_SUFFIX_SET.add(".properties");
    }

    /**
     * 需要過濾掉的目錄, 例如測試用例代碼所在目錄
     */
    private static final Set<String> EXCLUDE_DIRECTORY_SET = new HashSet<>();
    static {
        // 過濾掉/src/test目錄下的文件(即測試用例相關代碼)
        EXCLUDE_DIRECTORY_SET.add("src"+File.separator+"test");
        EXCLUDE_DIRECTORY_SET.add("target");
    }

    /**
     * 是否需要輸出文件或者目錄過濾與否的信息, 如果需要輸出, 還會輸出文件或者目標被過濾的原因: 無效文件or無效目錄
     */
    private static final boolean FILE_FILTER_INFO = true;

    /**
     * 是否過濾掉源碼中的註釋
     */
    private static final boolean FILTER_COMMENT = true;

    public static void main(String[] args) throws Exception{
        String target ;
        List<String> projectNameList = new ArrayList<>();
        projectNameList.add("sharding-jdbc");
        for(String projectName:projectNameList) {
            target = "C:\\ProjectCode\\" + projectName;
            System.out.println(target + "(" + projectName + ")總行數:" + lineCount(target));
        }
    }

    /**
     * 統計文件或者目錄下所有文件總行數
     * @param target 文件路徑或者目錄路徑
     * @return 文件或者目錄下所有文件總行數
     * @throws Exception
     */
    private static int lineCount(String target) throws Exception{
        // 先判斷是文件還是目錄
        File origin = new File(target);
        if (origin.isFile()){
            return fileCount(origin);
        }else{
            // 如果是目錄要遍歷
            return directoryCount(origin);
        }
    }

    private static int directoryCount(File dir) throws Exception {
        int sum = 0;

        File[] files = dir.listFiles();
        if (files==null){
            throw new IllegalArgumentException("無效的目錄:"+dir.getCanonicalPath());
        }

        for (File file:files){
            if (file.isFile()){
                sum += fileCount(file);
            }else{
                sum += directoryCount(file);
            }
        }
        return sum;
    }

    /**
     * 全路徑指定的文件所在目錄是否是需要exclude的目錄
     * @param path 文件的全路徑
     * @return 文件所在目錄是否是需要exclude的目錄
     */
    private static boolean invalidDirectory(String path){
        for (String dir: EXCLUDE_DIRECTORY_SET){
            if (path.contains(dir)){
                return true;
            }
        }

        return false;
    }

    /**
     * 全路徑指定的文件後綴是否是約定的合法文件後綴(VALID_SUFFIX_SET指定)
     * @param path 文件的全路徑
     * @return 是否是有效的文件
     */
    private static boolean validFile(String path){
        for (String suffix: VALID_SUFFIX_SET){
            if (path.endsWith(suffix)){
                return true;
            }
        }
        return false;
    }

    /**
     * 文件中內容行數統計
     * @param file 文件
     * @return 文件中內容總行數
     * @throws Exception
     */
    private static int fileCount(File file) throws Exception {

        String path = file.getCanonicalPath();

        boolean validFile = validFile(path);
        boolean invalidDirectory = invalidDirectory(path);
        if (!validFile || invalidDirectory){
            if (FILE_FILTER_INFO) {
                System.out.println("需要過濾的文件: " + path + ", " +(validFile?"無效目錄":"無效文件"));
            }
            return 0;
        }
        if (FILE_FILTER_INFO) {
            System.out.println("不需過濾的文件: " + path);
        }

        BufferedReader reader = new BufferedReader(new FileReader(file));
        int count = 0;

        String line;
        // readLine結果爲null表示讀到文件末尾了
        while((line = reader.readLine())!=null){
            // 行內容不爲空的話, 如果需要過濾註釋且不是註釋代碼行才自增, 如果不需要過濾註釋代碼行也自增;
            if (FILTER_COMMENT) {
                if (!isCommentLine(line)) {
                    ++count;
                }
            }else{
                //
                ++count;
            }
        }
        return count;
    }

    /**
     * 判斷這一行內容是否是註釋: 以/或者*開頭就認爲是註釋
     * @param line 一行內容
     * @return 是註釋則返回true, 否則返回false
     */
    private static boolean isCommentLine(String line){
        String content = line.trim();
        if (content.startsWith("/")
                || content.startsWith("*")){
            System.out.println("這一行內容是註釋: "+line);
            return true;
        }
        return false;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章