随笔 - 268  文章 - 0  评论 - 1028  阅读 - 160万

Sharing A Powerful Tool For Calculate Code Lines

最近正好需要统计下某项目代码行数,然后就找代码行数统计工具。以前找到过一个正则表达式,但是只有在VS2010下有用,VS2012和VS2013下的统计就不好使了。

接着搜索了一下代码行数统计绿色工具免费版,看到花花绿绿的浮动窗口和卧虎藏龙的下载链接,感觉非常令人生厌,而且,有些国产软件下载总是让你一不小心就中毒,所以最后还是放弃了下载。

当然,你知道,这点简单小功能,对于已经习惯自己搬砖搞定一切的码农,实在没有必要再费时间搜来搜去,而且那首歌唱得好,“Let it go,let it go...The code doesn‘t bother me anyway.”,所谓求人不如求己是也。

抽空自己写了这个代码行数分析winform工具,目前测试通过支持的语言有C#、Java、SQL、JavaScript和Python,共享出来,希望对你有帮助。

软件界面:

codecalc

一、程序简单分析

统计分析代码行数,需要分析源文件。这里的程序选择简单的打开源文件的方法,但是读取内容不是一下子全部读完,而是一行一行读取,读取后,需要按统计条件分析并计数。

统计条件抽象如下:

复制代码
using System;

namespace PowerCodeCalculator.Model
{
    /// <summary>
    /// 代码统计条件
    /// </summary>
    [Serializable]
    public sealed class CodeStatisticCondition
    {
        /// <summary>
        /// 代码目录 绝对路径 形如:D:\PowerCode
        /// </summary>
        public string CodeDirectory { get; set; }

        /// <summary>
        /// 统计的代码类型 通常为.cs代码文件
        /// </summary>
        public string FileTypeFilter { get; set; }

        /// <summary>
        /// 忽略统计的代码文件 如VS自动生成的.designer.cs文件等 多个以逗号,分隔
        /// </summary>
        public string IgnoreFileType { get; set; }

        /// <summary>
        /// 是否统计大括号{或}
        /// </summary>
        public bool IsCalcBrace { get; set; }

        /// <summary>
        /// 是否统计空行行数
        /// </summary>
        public bool IsCalcEmptyLine { get; set; }

        /// <summary>
        /// 是否统计注释行数
        /// </summary>
        public bool IsCalcComment { get; set; }

        /// <summary>
        /// 是否启用多线程统计
        /// </summary>
        public bool IsEnableMultiThread { get; set; }
    }
}
CodeStatisticCondition
复制代码

代码源文件信息CodeInfo抽象如下:

复制代码
using System;

namespace PowerCodeCalculator.Model
{
    /// <summary>
    /// 代码信息实体
    /// </summary>
    [Serializable]
    public sealed class CodeInfo
    {
        /// <summary>
        /// 文件名绝对路径 形如:c:\Program.cs
        /// </summary>
        public String FilePath { get; set; }

        /// <summary>
        /// 代码行数
        /// </summary>
        public Int64 LineCount { get; set; }

        /// <summary>
        /// 代码字符数
        /// </summary>
        public Int64 CharCount { get; set; }
    }
}
CodeInfo
复制代码

返回的源文件统计信息CodeStatisticInfo抽象如下:

复制代码
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;

namespace PowerCodeCalculator.Model
{
    /// <summary>
    /// 代码统计结果信息实体
    /// </summary>
    [Serializable]
    public sealed class CodeStatisticInfo
    {

        /// <summary>
        /// 是否成功
        /// </summary>
        public bool IsOK { get; set; }

        /// <summary>
        /// 代码总行数
        /// </summary>
        public Int64 TotalCount { get; set; }

        /// <summary>
        /// 代码字符总数
        /// </summary>
        public Int64 TotalCharCount { get; set; }

        /// <summary>
        /// 代码信息列表
        /// </summary>
        public List<CodeInfo> CodeInfoList { get; set; }

        /// <summary>
        /// 统计输出信息
        /// </summary>
        public String OutPutInfo { get; set; }
    }
}
CodeStatisticInfo
复制代码

主要统计的业务逻辑在CodeCounterService的Calc方法中:

复制代码
public static CodeStatisticInfo Calc(CodeStatisticCondition condition)
{
    //1、验证参数
    var statResult = CheckCondition(condition);
    if (statResult.IsOK == false)
    {
        return statResult;
    }

    //2、递归获取所有代码目录
    var dirList = GetFileDir(condition.CodeDirectory);

    //3、以目录为单位进行遍历统计
    try
    {
        if (condition.IsEnableMultiThread == false) //单线程统计
        {
            foreach (var dir in dirList)
            {
                var innerCodeInfoList = GetCodeInfoList(dir, condition);
                statResult.CodeInfoList.AddRange(innerCodeInfoList);
            }
        }
        else //多线程统计 待统计代码目录较多,文件较大或者个人PC配置渣渣的情况下请慎用
        {
            var taskCnt = 8; //并发任务数
            var dictDir = GetGroupDir(taskCnt, dirList);
            var taskFactory = new TaskFactory();
            foreach (var kv in dictDir)
            {
                PowerLogger.AppendLog("任务【{0}】,并发执行{1}个目录的代码统计", kv.Key, kv.Value.Count);
                var listTask = new List<Task<IList<CodeInfo>>>();
                foreach (var item in kv.Value)
                {
                    var notifyTask = taskFactory.StartNew<IList<CodeInfo>>
                    (
                        () => { return GetCodeInfoList(item, condition); }
                    );

                    listTask.Add(notifyTask);
                }

                Task.WaitAll(listTask.ToArray()); //等待一批任务并行执行完成

                foreach (var tmpTask in listTask)
                {
                    statResult.CodeInfoList.AddRange(tmpTask.Result);
                }
            }
        }
    }
    catch (Exception ex)
    {
        statResult.IsOK = false;
        statResult.OutPutInfo = string.Format("统计代码发生异常:{0}", ex);
    }
    if (statResult.IsOK == false)
    {
        return statResult;
    }

    //4、统计代码总行数及输出
    statResult.TotalCount = statResult.CodeInfoList.Sum(x => x.LineCount);
    statResult.TotalCharCount = statResult.CodeInfoList.Sum(x => x.CharCount);

    var sb = new StringBuilder(1024);
    sb.AppendFormat("代码总行数:{0}", statResult.TotalCount);
    sb.AppendLine();
    sb.AppendFormat("代码总字符数:{0}", statResult.TotalCharCount);
    sb.AppendLine();

    if (statResult.CodeInfoList.Any())
    {
        sb.Append("代码行数统计明细:");
        sb.AppendLine();
    }
    else
    {
        sb.Append("没有匹配的代码文件");
    }
    foreach (var codeInfo in statResult.CodeInfoList)
    {
        sb.Append(codeInfo.FilePath);
        sb.AppendLine();
        sb.AppendFormat("【代码行数】:{0}", codeInfo.LineCount);
        sb.AppendLine();
        sb.AppendFormat("【代码字符数】:{0}", codeInfo.CharCount);

        sb.AppendLine();
        sb.AppendLine();
    }

    statResult.OutPutInfo = sb.ToString();

    return statResult;
}
Calc
复制代码

 

二、存在的主要不足和缺点

1、不同语言统计支持没有经过充分测试

目前这个小程序仅仅验证了自己经常使用的几种开发语言,其他语言未验证是否通过。

2、多线程统计支持不好

代码中,我想用Task提升性能,目前测试下来,多线程比单线程耗时更久,非常不友好。本来计划使用多线程技术打开文件并行分析每个文件的代码行数,毕竟,IO和计算密集型程序在多线程下应该能够发挥优势。但是看到根据目录并发分析统计代码效果并不好,所以我就直接放弃了多文件同时分析的实现。

3、统计数据不精确

代码行数统计并不完全准确,“统计”的时候,可能某项目下已经无效的代码也加入了统计。还有就是注释,不同语言的注释解析是个难题。再比如说压缩后的js文件,这个也会造成解析统计的不准确。

 

demo地址:PowerCodeCalculator

可执行文件下载:PowerCodeCalculator.exe

posted on   JeffWong  阅读(1388)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2013-05-12 Java HashMap的死循环的启示
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

I know how to make it works and I want to know how it works.
点击右上角即可分享
微信分享提示