import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Created by zero on 2017/7/11.
*/
public class CodeCountTool {
ExecutorService es = Executors.newCachedThreadPool();
public static void main(String[] args) {
System.out.println("start...");
String[] targets = {".java"};
// todo add filter file types
File file = new File("D:\\projects\\myweb\\");
new CodeCountTool(targets).start(file);
System.out.println("end.");
}
private String[] targets;
public CodeCountTool(String[] targets) {
this.targets = targets;
}
public void start(File file) {
List<StatCount> statCounts = new ArrayList<>();
List<Future> futures = new ArrayList<>();
statFiles(file, statCounts, futures);
for (Future future : futures) {
try {
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
StatCount sc = new StatCount();
for (StatCount statCount : statCounts) {
sc.addCodeLine(statCount.getCodeCount());
sc.addSpace(statCount.getSpaceCount());
sc.addCommentLine(statCount.getCommentCount());
sc.addLine(statCount.getLineCount());
System.out.println(statCount.toString());
}
System.out.println(sc.toString());
}
public void statFiles(final File file, final List<StatCount> scList, List<Future> futures) {
if (file.isFile()) {
boolean isTarget = false;
String fileName = file.getName();
for (String target : targets) {
if (fileName.endsWith(target)) {
isTarget = true;
break;
}
}
if (isTarget) {
futures.add(es.submit(new Runnable() {
@Override
public void run() {
scList.add(count(file));
}
}));
}
} else if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
statFiles(f, scList, futures);
}
}
}
public StatCount count(File file) {
System.out.println(file.getName());
StatCount sc = new StatCount();
// File file = new File("D:\\projects\\hasoffer-server\\hasoffer.admin\\src\\main\\java\\hasoffer\\admin\\common\\CategoryHelper.java");
BufferedReader br = null;
String line;
boolean commentStart = false;
try {
br = new BufferedReader(new FileReader(file));
String status = "";
while ((line = br.readLine()) != null) {
sc.addLine();
String trimLine = line.trim();
/**
* 1、多行注释 2、多行注释中以双斜杠开头 3、双斜杠开头 *
*/
if (commentStart || trimLine.startsWith("//") || trimLine.startsWith("/*")) {
status = "注释:";
sc.addCommentLine();
if (trimLine.startsWith("/*")) {
commentStart = true;
}
} else if ("".equals(trimLine)) {
status = "空行:";
sc.addSpace();
} else {
status = "代码:";
sc.addCodeLine();
}
// System.out.println(status + line);
if (trimLine.endsWith("*/")) {
commentStart = false;
}
}
// System.out.println(String.format("总行数:%d", sc.getLineCount()));
// System.out.println(String.format("代码行数:%d", sc.getCodeCount()));
// System.out.println(String.format("注释行数:%d", sc.getCommentCount()));
// System.out.println(String.format("空行数:%d", sc.getSpaceCount()));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
return sc;
}
}
class StatCount {
private long lineCount;
private long codeCount;
private long commentCount;
private long spaceCount;
public void addCodeLine() {
codeCount++;
}
public void addCommentLine() {
commentCount++;
}
public void addLine() {
lineCount++;
}
public void addSpace() {
spaceCount++;
}
public void addCodeLine(long cl) {
codeCount += cl;
}
public void addCommentLine(long cl) {
commentCount += cl;
}
public void addLine(long l) {
lineCount += l;
}
public void addSpace(long s) {
spaceCount += s;
}
public long getLineCount() {
return lineCount;
}
public void setLineCount(long lineCount) {
this.lineCount = lineCount;
}
public long getCodeCount() {
return codeCount;
}
public void setCodeCount(long codeCount) {
this.codeCount = codeCount;
}
public long getCommentCount() {
return commentCount;
}
public void setCommentCount(long commentCount) {
this.commentCount = commentCount;
}
public long getSpaceCount() {
return spaceCount;
}
public void setSpaceCount(long spaceCount) {
this.spaceCount = spaceCount;
}
@Override
public String toString() {
return "StatCount{" +
"lineCount=" + lineCount +
", codeCount=" + codeCount +
", commentCount=" + commentCount +
", spaceCount=" + spaceCount +
'}';
}
}
上面的代码中两个方法可以修改一下,使用 Callable 代替 Runnable ,把statcount 对象通过返回值的方式返回,从而省去一次循环和一个list。代码如下:
public void start(File file) {
List<Future> futures = new ArrayList<>();
statFiles(file, futures);
StatCount sc = new StatCount();
for (Future future : futures) {
try {
StatCount statCount = (StatCount) future.get();
sc.addCodeLine(statCount.getCodeCount());
sc.addSpace(statCount.getSpaceCount());
sc.addCommentLine(statCount.getCommentCount());
sc.addLine(statCount.getLineCount());
System.out.println(statCount.toString());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.println(sc.toString());
}
public void statFiles(final File file, List<Future> futures) {
if (file.isFile()) {
boolean isTarget = false;
String fileName = file.getName();
for (String target : targets) {
if (fileName.endsWith(target)) {
isTarget = true;
break;
}
}
if (isTarget) {
futures.add(es.submit(new Callable<StatCount>() {
@Override
public StatCount call() throws Exception {
return count(file);
}
}));
}
} else if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
statFiles(f, futures);
}
}
}