遍历指定文件夹并统计代码行数,和Java关键字频率,降序输出所有结果。
默认统计.java文件,可以自定义统计其他源码。
打算将它整合到自己做的桌面小程序中。
部分输出如下:
代码总行数:11341
E:\java\以往习作\KingTetris.java--->行数:419
F:\EclipseProject\Test\src\king\countcode\CountCodeLine.java--->行数:340
F:\EclipseProject\记事本\src\king\notepad\view\NotepadFrame.java--->行数:332
F:\EclipseProject\五子棋\src\guyuanguanli.java--->行数:298
F:\EclipseProject\记事本\src\king\notepad\service\TextService.java--->行数:277
F:\EclipseProject\简易绘图板\src\King\Test.java--->行数:267
---------Java代码关键字统计:----------
关键字:new 出现次数:873
关键字:int 出现次数:668
关键字:public 出现次数:608
关键字:private 出现次数:520
关键字:null 出现次数:511
关键字:void 出现次数:413
关键字:static 出现次数:299
关键字:return 出现次数:293
关键字:if 出现次数:282
关键字:this 出现次数:232
关键字:class 出现次数:201
关键字:for 出现次数:161
关键字:true 出现次数:146
关键字:else 出现次数:92
关键字:final 出现次数:88
关键字:false 出现次数:79
关键字:case 出现次数:78
关键字:catch 出现次数:68
关键字:while 出现次数:67
关键字:try 出现次数:63
关键字:boolean 出现次数:60
关键字:extends 出现次数:56
关键字:implements 出现次数:55
关键字:throws 出现次数:45
关键字:break 出现次数:41
关键字:char 出现次数:40
关键字:super 出现次数:34
关键字:byte 出现次数:32
关键字:switch 出现次数:22
关键字:double 出现次数:17
关键字:abstract 出现次数:16
关键字:do 出现次数:15
关键字:protected 出现次数:13
关键字:synchronized 出现次数:9
关键字:long 出现次数:9
关键字:finally 出现次数:8
关键字:throw 出现次数:8
关键字:instanceof 出现次数:7
关键字:default 出现次数:6
关键字:float 出现次数:2
关键字:continue 出现次数:2
关键字:package 出现次数:2
关键字:transient 出现次数:2
关键字:import 出现次数:2
关键字:interface 出现次数:2
关键字:native 出现次数:2
关键字:volatile 出现次数:2
关键字:short 出现次数:2
关键字:strictfp 出现次数:1
关键字:enum 出现次数:1
关键字:const 出现次数:1
关键字:goto 出现次数:1
关键字:assert 出现次数:1
源码:
package king.countcode;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 统计指定目录下Java文件的总行数、关键字频率
*
*/
public class CountCodeLine {
private int count = 0;
// 所有需要遍历的文件
private List<File> allFile = new LinkedList<File>();
// 所有遍历结果
private Map<String, Integer> allResult = new HashMap<String, Integer>();
// 排序后的所有遍历结果
private List<Map.Entry<String, Integer>> allSortedResult = new LinkedList<Map.Entry<String, Integer>>();
// 需要检查的文件后缀,默认添加.java
private List<String> allSuffix = new LinkedList<String>();
private static final String JAVA_SUFFIX = ".java";
//提取单词的正则表达式
private Pattern p = Pattern.compile("(?<=\\W)\\w+(?=\\W)");
//用于计数
private Keywords countKeyword = new Keywords();
public CountCodeLine(){
addSuffix(JAVA_SUFFIX);
}
public static void main(String[] args) {
CountCodeLine count = new CountCodeLine();
// 添加需要检查的文件或文件夹
count.addPath("E:\\java");
count.addPath("F:\\EclipseProject");
// // 遍历C盘之外所有硬盘
// // 由于文件太多,全部遍历需要很久才能出结果,一般不建议
// File[] roots = File.listRoots();
// for(int i = 0; i < roots.length; i++){
// // C盘某些文件夹无权限进入,会报错,故剔除
// if (!roots[i].getAbsolutePath().toLowerCase().startsWith("c:")){
// count.addPath(roots[i].getAbsolutePath());
// }
// }
// 检查并返回统计 总行数
System.out.println("代码总行数:" + count.execute());
// 输出降序排列的总结果
for(Map.Entry<String, Integer> entry : count.getAllSortedResult()){
System.out.println(entry.getKey() + "--->行数:" + entry.getValue());
}
//输出所有Java文件中的关键字频率统计
// 如果想统计单个文件,请在上方addPath()仅输入单个文件的绝对地址
System.out.println();
System.out.println("---------Java代码关键字统计:----------");
System.out.println(count.getUsedKeywordFrequency());
}
/*
* 添加需要检查的文件或文件夹
*/
public void addPath(String path){
allFile.add(new File(path));
}
/*
* 添加需要检查的后缀名
* 如果要用来统计其他后缀名的文件,请先clear()
*/
public void addSuffix(String suffix){
suffix = suffix.toLowerCase(); //全转小写
if (!suffix.startsWith(".")) suffix = "." + suffix;
allSuffix.add(suffix);
}
/*
* 开始遍历
*/
public int execute(){
for(File file : allFile){
checkFile(file);
}
// 排序所有结果
sortAllResult();
return getCount();
}
/*
* 获取当前count值
*/
public int getCount(){
return count;
}
/*
* 返回详细的结果
* 文件名-代码行数映射的Set<Map.Entry<String, Integer>>
*/
public Set<Map.Entry<String, Integer>> getAllResult(){
return allResult.entrySet();
}
/**
* 返回所有排序后的结果
*/
public List<Map.Entry<String, Integer>> getAllSortedResult(){
return new LinkedList<Map.Entry<String, Integer>>(allSortedResult);
}
/**
* 返回关键字频率的统计结果
* @return
*/
public String getUsedKeywordFrequency(){
return countKeyword.getUsedKeywordFrequency();
}
/*
* 清空所有内容,以便开始全新的查找
*/
public void clear(){
count = 0;
allFile.clear();
allResult.clear();
allSortedResult.clear();
allSuffix.clear();
}
/*
* 遍历文件夹
*/
private void checkFile(File file){
if (file.isDirectory()){
File[] files = file.listFiles();
for(File f : files){
checkFile(f);
}
} else if (checkSuffix(file)){
countLine(file);
}
// // 下面是循环方法,当递归溢出时,可改用循环
// Stack<File> stack = new Stack<File>();
// stack.push(file);
// while(!stack.isEmpty()){
// File tmp = stack.pop();
// if (tmp.isDirectory()){
// File[] files = tmp.listFiles();
// for (File f : files){
// stack.push(f);
// }
// } else if (checkSuffix(tmp)){
// countLine(tmp);
// }
// }
}
/**
* 检查后缀名
*/
private boolean checkSuffix(File file){
String fileName = file.getName().toLowerCase();
for(String suffix : allSuffix){
if (fileName.endsWith(suffix)) return true;
}
return false;
}
/*
* 统计Java文件的行数
*/
private void countLine(File file){
try (BufferedReader input = new BufferedReader(new FileReader(file))){
String str = null;
int tmpCount = 0;
while ((str = input.readLine()) != null){
// 检查这一行里的每一个单词
Matcher m = p.matcher(str);
while(m.find()){
// 判断是否Java关键字
countKeyword.checkWord(m.group());
}
tmpCount++;
}
count += tmpCount;
allResult.put(file.getAbsolutePath(), tmpCount); //保存到集合中
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 排序所有统计结果
* 降序
*/
private void sortAllResult(){
allSortedResult.addAll(allResult.entrySet());
Collections.sort(allSortedResult, new Comparator<Map.Entry<String, Integer>>(){
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2){
int value1 = o1.getValue();
int value2 = o2.getValue();
if (value1 == value2) return 0;
return value1 > value2 ? -1 : 1;
}
});
}
}
//关键字集合,用于计数
class Keywords {
// 所有关键字
private Map<String, Integer> keywords = new HashMap<String, Integer>();
//构造器
public Keywords(){
reset();
}
//复位清零
public void reset(){
for(Keyword k : Keyword.values()){ //从枚举类获取关键字
keywords.put(k.getKeyword(), 0);
}
}
//检测一个单词是否关键字,如果是,就让对应的关键字频数加1
public void checkWord(String word){
if (keywords.keySet().contains(word)){
keywords.put(word, keywords.get(word) + 1);
}
}
//返回统计结果
public String getUsedKeywordFrequency(){
StringBuilder result = new StringBuilder();
StringBuilder tmp = new StringBuilder();
//按频数即value值排序
//就算用TreeMap也只能对key排序,下面用自己写的比较器排序
//继承Comparator接口改改名compare方法后,TreeSet会认为compare结果为0的两个元素是同一个元素,故不用TreeSet
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(keywords.entrySet());
Collections.sort(list, new MyMapEntryComparator());
for(Map.Entry<String, Integer> entry : list){
if (entry.getValue() != 0){
tmp.setLength(0);
tmp.append("关键字:").append(entry.getKey()).append("出现次数:").append(entry.getValue());
result.append(typeset(tmp)).append("\n");
}
}
return result.toString();
}
/**
* 将字符串排版再返回,如下输出不整齐
* 关键字:null 出现次数:1
* 关键字:implements 出现次数:1
* 控制“关键字”和“出现次数”之间的空格,
* 将来可能改变输出的汉字,故下面用正则式考虑更广泛的情况
* @param StringBuilder
* @return String
*/
private String typeset(StringBuilder sb){
StringBuilder result = new StringBuilder();
int blank = 15; //不同组汉字之间的空白
int index = 0, length = 0, differ;
//找出右边不是紧邻汉字的汉字,向后数十五个空
Pattern p = Pattern.compile("(?<![一-龥])[一-龥]+(?![一-龥])");
Matcher m = p.matcher(sb);
while(m.find()){ //find()后移一位
result.append(sb.substring(index, m.start()));
if((differ = blank -(m.start() - index - length)) > 0 && m.start() != 0){
while(differ-- > 0){
result.append(" ");
}
}
index = m.start();
length = m.group().length();
}
//如果后面中文,则把剩下的全接上去
result.append(sb.substring(index));
return result.toString();
}
//比较用的Comparator,只在这时用到,故写成内部类
private class MyMapEntryComparator implements Comparator<Map.Entry<String, Integer>>{
@Override
public int compare(Map.Entry<String, Integer> m1, Map.Entry<String, Integer> m2){
return -(m1.getValue() - m2.getValue());
}
}
}
//所有关键字,枚举类,仅用于存储
enum Keyword{
ABSTRACT("abstract"), ASSERT("assert"), BOOLEAN("boolean"), BREAK("break")
, BYTE("byte"), CASE("case"), CATCH("catch"), CHAR("char"), CLASS("class")
, CONST("const"), CONTINUE("continue"), DEFAULT("default"), DO("do"), DOUBLE("double")
, ELSE("else"), ENUM("enum"), EXTENDS("extends"), FALSE("false"), FINAL("final")
, FINALLY("finally"), FLOAT("float"), FOR("for"), GOTO("goto"), IF("if")
, IMPLEMENTS("implements"), IMPORT("import"), INSTANCEOF("instanceof"), INT("int")
, INTERFACE("interface"), LONG("long"), NATIVE("native"), NEW("new"), NULL("null")
, PACKAGE("package"), PRIVATE("private"), PROTECTED("protected"), PUBLIC("public")
, RETURN("return"), SHORT("short"), STATIC("static"), STRICTFP("strictfp")
, SUPER("super"), SWITCH("switch"), SYNCHRONIZED("synchronized"), THIS("this")
, THROW("throw"), THROWS("throws"), TRANSIENT("transient"), TRY("try"), TRUE("true")
, VOID("void"), VOLATILE("volatile"), WHILE("while");
private String keyword;
//构造器
private Keyword(String keyword){
this.keyword = keyword;
}
//获取keyword
public String getKeyword() {
return keyword;
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。