简介:Source Counter是一款面向软件开发团队与项目管理者的代码统计工具,用于量化代码行数、注释行与空行,辅助评估开发工作量、项目进度与代码质量。它支持C++、Java、Python、JavaScript等多种语言,可对指定目录或单个文件快速扫描并生成统计报告,还能基于环路复杂度等指标分析代码维护难度,帮助识别潜在代码异味。资源包共45个文件,以32个png界面截图、3个dll动态链接库、2个mo多语言文件及2个html报告模板为主,另含exe主程序、ico图标、dat数据与xml配置,压缩包约2.31MB,整体轻量,解压即可运行。其中dll组件来自MinGW与wxWidgets环境,locales目录提供中英日等多语言支持,conf目录可自定义统计参数与报告格式。目前已有749人学习下载,适合需要项目规划、代码质量检查或团队绩效评估的开发者参考使用。
1. 代码统计工具 Source Counter:为什么老项目交接前我总要跑一遍
接手一个跑了三年以上的老项目,最怕的不是代码烂,而是没人说得清它到底有多大。上次帮朋友看一个“小工具”,打开目录一看,node_modules、dist、.git全在里面,用编辑器自带的统计功能一跑,显示 47 万行,当场就想关电脑。后来用 Source Counter 这类专门的代码统计工具重新扫了一遍,排除掉依赖和构建产物,真实业务代码不到 3 万行。这个差距,直接决定了你评估工作量、排期和报价的底气。
Source Counter 就是干这个的:它按文件类型、目录层级去统计代码行数、注释行数、空行数,把有效代码和噪音分开。适合谁用?接私活要估工作量的、做代码审计要摸清体量的、维护老系统要写交接文档的,还有学生做课程设计想看看自己到底写了多少行的。它不编译、不运行你的代码,只做静态扫描,所以对任何语言的项目都能上手。下面把我自己用的流程和踩过的坑拆开讲。
2. 把 Source Counter 跑起来:从安装到第一次有效扫描
2.1 选型理由:为什么不用编辑器自带统计
编辑器自带的统计功能,比如 VS Code 的“Count Lines”,或者wc -l一把梭,最大的问题是不区分文件类型和目录。你对着一个 Java 项目跑find . -name "*.java" | xargs wc -l,确实能出数,但target/目录下的编译产物、src/test/里的测试代码、自动生成的*Generated.java全混在一起。Source Counter 的核心价值在于过滤规则可配置:你可以按扩展名指定只统计哪些文件,按目录名排除哪些文件夹,还能把注释行和空行单独列出来。对于需要向非技术人员解释“这个项目有多大”的场景,一张分语言、分目录的统计表比一个总数有用得多。
常见做法是:先跑一次全量扫描,看看有哪些文件类型冒出来,再根据结果调整排除规则。我一般会先把.git、node_modules、vendor、dist、build、target、out这些目录全部排除,然后按语言分组看结果。
2.2 安装与基础配置
Source Counter 有多个版本和分支,有带图形界面的,也有命令行工具。我习惯用命令行版本,方便写进脚本里重复跑。假设你拿到的是一个可执行文件或者通过包管理器安装的版本,基础用法如下:
# 基础扫描:统计当前目录下所有支持的文件类型 source-counter scan --path ./my-project --output report.txt # 指定只统计特定扩展名 source-counter scan --path ./my-project --include "*.java,*.xml,*.sql" --output report.txt # 排除目录(多个用逗号分隔) source-counter scan --path ./my-project --exclude "node_modules,dist,.git,target" --output report.txt这里--path指定项目根目录,--include和--exclude是过滤规则。注意--exclude匹配的是目录名或文件名模式,不是完整路径,所以写node_modules就能排除任意层级的该目录。--output把结果写到文件,方便后续对比。
如果你用的是图形界面版本,操作逻辑类似:在设置里找到“文件过滤器”或“排除模式”,把上面那些目录名填进去,然后点“开始统计”。图形界面的好处是能直接看到目录树和每个文件的明细,适合一次性分析;命令行适合集成到 CI 或定期跑。
2.3 读懂统计报告:哪些数字真正有用
跑完一次扫描,报告里通常会有这几列:文件数、总行数、代码行、注释行、空行、注释率。很多人只看“总行数”,这是最容易翻车的地方。总行数包含空行和注释,不能代表实际工作量。我一般关注三个指标:
- 代码行(Code Lines):去掉空行和注释后的有效行,这是评估工作量的基准。
- 注释率(Comment Ratio):注释行除以代码行,低于 5% 说明文档稀薄,交接时要多留时间。
- 文件类型分布:如果
.json或.xml占了很大比例,要警惕配置文件膨胀,真正逻辑代码可能很少。
举个例子,一个 Spring Boot 项目扫描结果如下:
| 文件类型 | 文件数 | 代码行 | 注释行 | 空行 | 注释率 |
|---|---|---|---|---|---|
| .java | 142 | 18,230 | 2,105 | 3,420 | 11.5% |
| .xml | 38 | 4,560 | 320 | 890 | 7.0% |
| .sql | 12 | 1,240 | 180 | 210 | 14.5% |
| .yml | 8 | 320 | 45 | 60 | 14.1% |
看到.java代码行 1.8 万,注释率 11.5%,说明项目有一定文档基础,但不算特别完善。.xml代码行 4560,要确认是 MyBatis 映射文件还是 Spring 配置,前者算业务逻辑,后者算配置。这些判断直接影响你对项目复杂度的评估。
提示:第一次扫描后,把报告里的文件类型分布和目录分布都看一遍,再决定要不要调整过滤规则。不要直接拿第一次的结果去报价。
3. 过滤规则与参数调优:让统计结果贴近真实工作量
3.1 排除目录的优先级与常见误伤
排除目录看起来简单,但顺序和模式写错,结果会差很多。Source Counter 的排除逻辑通常是先匹配排除规则,再统计剩余文件。如果你把src排除了,那所有源码都没了;如果你只写test,那src/test和test-utils都会被干掉,后者可能包含你要统计的工具类。
我一般按这个优先级写排除列表:
- 版本控制目录:
.git、.svn、.hg - 依赖目录:
node_modules、vendor、bower_components、packages - 构建输出:
dist、build、target、out、bin、obj - 缓存与临时文件:
.cache、.tmp、tmp、temp - 测试资源:
test-data、fixtures、mocks(如果测试代码不计入工作量) - IDE 配置:
.idea、.vscode、.settings
但要注意误伤:有些项目把核心代码放在build目录下(比如某些老式 Ant 项目),或者把工具类放在test-utils里。排除之前,先手动ls一下这些目录,确认里面没有你要统计的东西。
# 先列出所有一级目录,人工确认哪些该排除 ls -d */ # 再用排除规则跑一次,对比文件数变化 source-counter scan --path ./my-project --exclude ".git,node_modules,dist,build,target,out,bin,obj,.cache,.tmp" --output report-filtered.txt跑完后对比report.txt和report-filtered.txt的文件数差异。如果差异过大(比如从 5000 个文件降到 200 个),说明排除规则可能太激进,需要逐条检查。
3.2 按扩展名包含:只统计你关心的语言
--include参数用来指定只统计哪些扩展名。常见做法是:先不写--include跑一次全量,看看报告里有哪些扩展名,再把不相关的去掉。比如一个 Web 项目可能包含.html、.css、.scss、.less、.js、.jsx、.ts、.tsx、.vue、.json、.md、.svg、.png等。如果你只关心逻辑代码,可以只保留.js、.ts、.vue、.java、.py这些。
# 只统计后端逻辑代码 source-counter scan --path ./my-project --include "*.java,*.kt,*.xml,*.sql,*.yml" --exclude ".git,target,build" --output backend-report.txt # 只统计前端逻辑代码 source-counter scan --path ./my-project --include "*.js,*.jsx,*.ts,*.tsx,*.vue,*.scss,*.less" --exclude "node_modules,dist,.git" --output frontend-report.txt这样分开统计的好处是:前后端工作量一目了然,报价时能分别说明。如果混在一起,客户可能觉得“不就一个网站吗”,分开后他看到后端 1.5 万行、前端 8000 行,沟通起来更有依据。
3.3 注释行与空行的处理策略
Source Counter 默认会把注释行和空行单独统计,但不同语言对注释的定义不一样。比如 Python 的#和"""都算注释,但"""有时是多行字符串,不是注释。Java 的//和/* */都算注释,但 Javadoc 的/** */也算。有些工具会把# TODO这种行算作代码行,有些算注释行,结果会有差异。
我一般会做两次统计:一次把注释行算进去,一次不算,对比差异。如果注释率超过 30%,要警惕是不是把大段注释掉的代码也算进去了——那些不是文档,是死代码。
# 统计时把注释行单独输出,方便人工检查 source-counter scan --path ./my-project --include "*.java" --exclude "target" --show-comments --output java-with-comments.txt # 只看代码行,忽略注释和空行 source-counter scan --path ./my-project --include "*.java" --exclude "target" --code-only --output java-code-only.txt--show-comments会把注释内容也输出到报告里,方便你抽查。如果发现大量// TODO或// FIXME,说明项目技术债不少,交接时要重点提醒。--code-only则直接过滤掉注释和空行,只留有效代码行,适合快速估算工作量。
注意:不同版本的 Source Counter 参数名可能略有差异,如果
--show-comments报错,试试--comments或-c。以你手头版本的--help输出为准。
4. 避坑与排查:统计结果和实际差三倍是怎么回事
4.1 现象:统计出 50 万行,实际业务代码不到 5 万
原因:最常见的是没有排除依赖目录和构建产物。node_modules里一个包就可能几万行,dist里的压缩 JS 一行能顶几千行。另外,有些项目把第三方库直接放在lib或vendor目录下,这些也不该算业务代码。
解决:先跑一次全量扫描,按目录排序看哪个目录行数最多。如果是node_modules或vendor,加进排除列表。如果是lib,打开看看是不是第三方库,是的话也排除。如果是src下的某个子目录异常大,检查是不是有自动生成的代码(比如 gRPC 生成的*Grpc.java、Protocol Buffers 生成的*OuterClass.java)。
# 按目录统计行数,快速定位异常目录 source-counter scan --path ./my-project --group-by directory --sort-by lines --output dir-ranking.txt--group-by directory会按目录汇总,--sort-by lines按行数降序排列。排在前面的目录就是重点排查对象。
4.2 现象:同一个项目两次扫描结果不一样
原因:可能是扫描过程中有文件被修改,或者过滤规则不一致。另外,有些工具会缓存上次结果,如果没清缓存,第二次可能读到旧数据。
解决:每次扫描前确认工作区是干净的(git status没有未提交改动),并且用相同的参数。如果工具支持--no-cache或--fresh,加上这个参数强制重新扫描。
# 确保工作区干净 git status --short # 强制重新扫描,不使用缓存 source-counter scan --path ./my-project --exclude ".git,node_modules,dist" --no-cache --output report-fresh.txt如果两次结果仍有差异,检查是否有文件在扫描期间被 IDE 自动保存或格式化。我一般会在扫描前关掉自动保存,或者直接用git stash暂存改动。
4.3 现象:注释率显示 0%,但代码里明明有注释
原因:可能是文件扩展名没被识别为支持注释的语言,或者注释符号不在工具的识别范围内。比如.vue文件里<template>部分的 HTML 注释<!-- -->,有些工具不认。另外,如果用了非标准注释风格(比如某些模板引擎的<%-- --%>),也可能漏掉。
解决:先确认文件扩展名在工具的“支持语言”列表里。如果不在,试试用--include强制包含,或者换一个支持该语言的统计工具。对于.vue文件,可以分别统计<script>和<template>部分,或者用专门的前端统计工具。
# 检查工具支持的语言列表 source-counter --list-languages # 如果 .vue 不在列表里,试试用 --include 强制包含 source-counter scan --path ./my-project --include "*.vue" --exclude "node_modules" --output vue-report.txt如果强制包含后注释率还是 0%,打开报告看看是不是把整个文件都算成代码行了。有些工具对混合语言文件处理不好,会把<template>里的 HTML 也当成代码行,注释自然就漏了。
4.4 现象:排除规则写了但没生效
原因:排除规则的匹配方式可能是完整路径匹配而不是目录名匹配。比如你写--exclude "node_modules",但工具实际匹配的是./node_modules或/absolute/path/node_modules,导致没匹配上。另外,多个排除项之间的分隔符可能是空格而不是逗号,写错了也会失效。
解决:先看工具的--help里排除参数的说明,确认匹配模式和分隔符。常见做法是:用*通配符,比如--exclude "*/node_modules/*"或--exclude "**/node_modules/**"。如果支持正则,用.*node_modules.*。
# 试试用通配符匹配任意层级的 node_modules source-counter scan --path ./my-project --exclude "**/node_modules/**,**/dist/**,**/.git/**" --output report-wildcard.txt # 如果还是不行,用绝对路径试试 source-counter scan --path ./my-project --exclude "/home/user/my-project/node_modules,/home/user/my-project/dist" --output report-abs.txt跑完后对比文件数,如果和全量扫描一样,说明排除规则完全没生效。这时候要么换参数写法,要么在工具配置文件里写排除规则(有些工具支持.sourcecounterignore文件,类似.gitignore)。
4.5 现象:统计结果里出现了二进制文件
原因:--include写得太宽泛,比如--include "*"会把所有文件都算进去,包括.png、.jpg、.exe、.dll。这些文件按行统计没有意义,还会把总行数拉得很大。
解决:明确指定要统计的扩展名,不要用*。如果确实需要统计所有文本文件,用--exclude把常见二进制扩展名排除掉:.png、.jpg、.jpeg、.gif、.ico、.svg、.woff、.woff2、.ttf、.eot、.mp3、.mp4、.zip、.tar、.gz、.jar、.war、.exe、.dll、.so、.dylib。
# 排除常见二进制文件 source-counter scan --path ./my-project --exclude ".git,node_modules,dist" --exclude-ext ".png,.jpg,.jpeg,.gif,.ico,.woff,.woff2,.ttf,.eot,.mp3,.mp4,.zip,.tar,.gz,.jar,.war,.exe,.dll,.so,.dylib" --output report-no-binary.txt--exclude-ext是按扩展名排除,比--exclude更精准。如果工具不支持这个参数,就把这些扩展名从--include里去掉。
5. 进阶技巧:把统计结果变成可对比的基线
5.1 建立项目基线,追踪代码量变化
单次统计只能看当前状态,真正有用的是对比。我习惯在项目启动时跑一次基线统计,之后每周或每个迭代跑一次,看代码行数的变化趋势。如果某周代码行突然暴涨,要么是加了大功能,要么是有人提交了生成代码或依赖目录。
# 第一次:建立基线 source-counter scan --path ./my-project --include "*.java,*.xml,*.sql" --exclude ".git,target,build" --output baseline-2025-01-01.txt # 之后每周跑一次,文件名带日期 source-counter scan --path ./my-project --include "*.java,*.xml,*.sql" --exclude ".git,target,build" --output weekly-2025-01-08.txt # 用 diff 对比两次结果(如果报告是纯文本且格式一致) diff baseline-2025-01-01.txt weekly-2025-01-08.txt如果报告格式是 CSV 或 JSON,可以用脚本解析后对比。我一般会写个简单的 Python 脚本,读取两次报告,计算代码行、注释行、文件数的变化量,输出一个对比表。
import csv def read_report(path): """读取 Source Counter 的 CSV 报告,返回 {文件类型: 代码行} 字典""" result = {} with open(path, 'r', encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: # 假设 CSV 列名为: Language, Files, CodeLines, CommentLines, BlankLines lang = row['Language'] result[lang] = { 'files': int(row['Files']), 'code': int(row['CodeLines']), 'comment': int(row['CommentLines']), 'blank': int(row['BlankLines']) } return result def compare(baseline_path, current_path): """对比两次统计结果,输出变化量""" base = read_report(baseline_path) curr = read_report(current_path) all_langs = set(base.keys()) | set(curr.keys()) print(f"{'语言':<12} {'代码行变化':>10} {'注释行变化':>10} {'文件数变化':>10}") for lang in sorted(all_langs): b = base.get(lang, {'code': 0, 'comment': 0, 'files': 0}) c = curr.get(lang, {'code': 0, 'comment': 0, 'files': 0}) print(f"{lang:<12} {c['code']-b['code']:>+10} {c['comment']-b['comment']:>+10} {c['files']-b['files']:>+10}") if __name__ == '__main__': compare('baseline-2025-01-01.csv', 'weekly-2025-01-08.csv')这个脚本假设报告是 CSV 格式,列名是Language、Files、CodeLines、CommentLines、BlankLines。如果你的报告列名不同,改一下DictReader里的键名就行。跑出来的对比表能直观看到哪种语言在增长、注释有没有跟上。
5.2 用统计结果辅助代码审查
代码审查时,除了看 diff,我还会看统计报告里的注释率变化。如果某个模块代码行增加了 2000 行,但注释行只增加了 50 行,说明新代码文档不足,审查时要重点看可读性。另外,如果某个文件的代码行数超过 1000 行,通常建议拆分,统计报告能帮你快速定位这些“巨型文件”。
# 按文件统计,找出代码行最多的文件 source-counter scan --path ./my-project --include "*.java" --exclude "target" --group-by file --sort-by code-lines --top 20 --output top-files.txt--group-by file按文件汇总,--sort-by code-lines按代码行排序,--top 20只显示前 20 个。排在前面的就是需要重点审查或拆分的文件。
5.3 一个具体技巧:用统计结果反推技术栈
有时候拿到一个老项目,没有文档,不知道用了什么技术栈。跑一次 Source Counter,看文件类型分布就能猜个大概:
- 大量
.java+.xml+.properties→ Spring 或 Java EE 项目 - 大量
.py+.html+.js→ Django 或 Flask 项目 - 大量
.php+.tpl+.js→ 老式 PHP 项目 - 大量
.vue+.js+.scss→ Vue 前端项目 - 大量
.kt+.xml→ Android 项目 - 大量
.swift+.storyboard→ iOS 项目
再结合注释率判断代码质量:注释率低于 3% 说明文档极差,交接成本高;注释率高于 20% 说明文档详细,但也要警惕是不是注释掉的死代码。我一般会把统计报告和git log结合看:如果最近半年提交很少,但代码量很大,说明是遗留系统,维护时要格外小心。
从那以后,我每次接手新项目,第一件事就是跑一遍 Source Counter,把基线报告存进项目文档里。后面每次迭代结束再跑一次,对比变化。这个习惯帮我避免了好几次“看起来很小其实很大”的坑,也让我在报价时更有底气。希望帮到你。
本文还有配套的精品资源,点击获取