话说之前直接用eclipse的代码行数统计,但是只能统计文件所有行数,不能统计具体的代码,我按照VC的那个统计行数的插件仿着写了个。。
统计指定扩展名下的总行数、纯代码行数、纯注释行数、代码混合注释行数、空行数以及非空行数。
下面是计算代码,可以控制台调用:
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Scanner;
- import java.io.File;
- import java.io.FileNotFoundException;
- /**
- * 统计行数
- * @author YOYO
- */
- public class LineCounter
- {
- /** 搜索的文件扩展名 */
- public List<String> fileExts = new ArrayList<String>();
- /** 纯代码行数 */
- private int codeLines = 0;
- /** 代码与注释同一行的行数 */
- private int codeWithCommentLines = 0;
- /** 注释行数 */
- private int commentLines = 0;
- /** 空白行数 */
- private int blankLines = 0;
- /**
- * 搜索的扩展名
- */
- public void setFileExts(String... exts) {
- fileExts.clear();
- for (String ext: exts) {
- fileExts.add(ext);
- }
- }
- /**
- * 总行数
- */
- public int getTotalLines() {
- return codeLines + codeWithCommentLines + commentLines + blankLines;
- }
- /**
- * 代码行数
- */
- public int getCodeLines() {
- return codeLines;
- }
- /**
- * 注释行数
- */
- public int getCommentLines() {
- return commentLines;
- }
- /**
- * 代码混合注释行数
- */
- public int getCodeWithCommentsLines() {
- return codeWithCommentLines;
- }
- /**
- * 空行数
- */
- public int getBlankLines() {
- return blankLines;
- }
- /**
- * 非空行数
- */
- public int getNonBlankLines() {
- return getTotalLines() - blankLines;
- }
- /**
- * 打印结果
- */
- public void printResult() {
- int totalLines = codeLines + codeWithCommentLines + commentLines + blankLines;
- int nonblankLines = totalLines - blankLines;
- System.out.println("=========================================");
- System.out.println("Total Lines : " + totalLines);
- System.out.println("Only Codes : " + codeLines);
- System.out.println("Only Comment : " + commentLines);
- System.out.println("Code With Comments : " + codeWithCommentLines);
- System.out.println("Blank Lines : " + blankLines);
- System.out.println("Non-Blank Lines : " + nonblankLines);
- System.out.println("=========================================");
- }
- /**
- * 统计行数
- * @param folder 项目路径
- */
- public void count(String folder) {
- File file = new File(folder);
- if (null == file) {
- return;
- }
- // 目录 则遍历子文件与文件夹
- if (file.isDirectory()) {
- for (String fileName: file.list()) {
- count(file.getPath() + "//" + fileName);
- }
- } else {
- // 检查是否需要统计的文件类型
- boolean flag = false;
- for (String ext: fileExts) {
- if (folder.endsWith(ext)) {
- flag = true;
- break;
- }
- }
- if (!flag) {
- return;
- }
- // 统计文件行数
- try {
- Scanner scanner = new Scanner(file);
- String line = null;
- boolean isComment = false;
- while (scanner.hasNext()) {
- line = scanner.nextLine();
- // 如果已经有注释开头
- if (isComment) {
- int pos = exist(line, "*/");
- if (pos != -1) {
- isComment = false;
- line = line.substring(0, pos).trim();
- // 以*/结尾的为纯注释句
- if (line.length() == 0) {
- ++commentLines;
- continue;
- }
- // 同时包含/*的,判断最后一个位置
- pos = exist(line, "/*");
- if (pos != -1) {
- if (existLast(line, "/*") > existLast(line, "*/"))
- {
- // 如果最后是/* 则依然在注释状态
- isComment = true;
- } else {
- isComment = false;
- }
- // 判断中间是否夹杂代码
- if (hasCodes(line)) {
- ++codeWithCommentLines;
- } else {
- ++commentLines;
- }
- } else {
- // 不包含/*且*/之后还有其他字符,则是代码混合注释
- ++codeWithCommentLines;
- }
- } else {
- // 不包含*/为纯注释句
- ++commentLines;
- }
- continue;
- }
- int pos = exist(line, "//");
- if (pos != -1) {
- if (line.trim().startsWith("//")) {
- // 以//打头,纯注释
- ++commentLines;
- } else {
- // 并非//打头,代码混合注释
- ++codeWithCommentLines;
- }
- continue;
- }
- // 如果包含
- pos = exist(line, "/*");
- if (pos != -1) {
- // 同时包含*/的,判断最后一个位置
- pos = exist(line, "*/");
- if (pos != -1) {
- if (existLast(line, "/*") > existLast(line, "*/")) {
- // 如果最后是/* 则依然在注释状态
- isComment = true;
- } else {
- isComment = false;
- }
- // 判断中间是否夹杂代码
- if (hasCodes(line)) {
- ++codeWithCommentLines;
- } else {
- ++commentLines;
- }
- } else {
- isComment = true;
- ++commentLines;
- }
- continue;
- }
- // 空行
- if (line.trim().length() == 0) {
- ++blankLines;
- continue;
- }
- // 不包含//,则是纯代码
- ++codeLines;
- }
- }
- catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- }
- }
- private int exist(String line, String substr) {
- int len = 0;
- while (true) {
- if (line.length() < len) {
- return -1;
- }
- String str = line.substring(len);
- if (!str.contains(substr)) {
- return -1;
- }
- str = str.substring(0, str.indexOf(substr));
- int t = 0;
- for (int i = 0; i < str.length(); ++i) {
- if (str.charAt(i) == '"' && (i == 0 || str.charAt(i - 1) != '//')) {
- ++t;
- }
- }
- if (t % 2 == 0) {
- return len + str.length();
- }
- len = str.length() + 1;
- }
- }
- private int existLast(String line, String substr) {
- int len = line.length();
- while (true) {
- String str = line.substring(0, len);
- if (!str.contains(substr)) {
- return -1;
- }
- str = str.substring(0, str.lastIndexOf(substr));
- int t = 0;
- for (int i = 0; i < str.length(); ++i) {
- if (str.charAt(i) == '"') {
- ++t;
- }
- }
- if (t % 2 == 0) {
- return str.length();
- }
- len = str.length() - 1;
- }
- }
- private boolean hasCodes(String line) {
- if (line.length() == 0) {
- return false;
- }
- return false;
- }
- public static void main(String[] args)
- {
- String folder = null;
- if (args.length == 0) {
- System.out.print("Input Your Project Directory >> ");
- Scanner scanner = new Scanner(System.in);
- folder = scanner.nextLine();
- } else {
- folder = args[0];
- }
- LineCounter counter = new LineCounter();
- counter.setFileExts(".java", ".jsp");
- counter.count(folder);
- counter.printResult();
- }
- }
顺便做了一个壳,调用该类进行计算,对文件的扩展名米有测试,截图如下,选中打开的目录后即开始计算并将结果显示。
根据项目文件的数量、代码行数的多少,效率会有差别。。
UI代码:
- import java.awt.Component;
- import java.awt.Dimension;
- import java.awt.FlowLayout;
- import java.awt.GridLayout;
- import java.awt.Toolkit;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.io.File;
- import javax.swing.JButton;
- import javax.swing.JFileChooser;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- import javax.swing.JPanel;
- import javax.swing.JTextField;
- public class LineCounterUI extends JFrame {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- private JTextField tfTotalLines = new JTextField("0");
- private JTextField tfCodeLines = new JTextField("0");
- private JTextField tfCommentLines = new JTextField("0");
- private JTextField tfCodeWithCommentLines = new JTextField("0");
- private JTextField tfBlankLines = new JTextField("0");
- private JTextField tfNonBlankLines = new JTextField("0");
- private JTextField tfExts = new JTextField(".java, .jsp, .js", 16);
- public LineCounterUI() {
- this.configures();
- this.fillComponents();
- this.setVisible(true);
- }
- private void configures() {
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- this.setTitle("统计行数用");
- this.setSize(450, 180);
- this.setLocation((int) (Toolkit.getDefaultToolkit().getScreenSize()
- .getWidth() - this.getWidth()) / 2, (int) (Toolkit
- .getDefaultToolkit().getScreenSize().getHeight() - this
- .getHeight()) / 2);
- }
- private void fillComponents() {
- this.setLayout(new FlowLayout());
- this.add(new JPanel() {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- {
- this.setPreferredSize(new Dimension(400, 100));
- this.setLayout(new GridLayout(4, 6));
- this.add(new JLabel("Total Lines", JLabel.CENTER));
- this.add(new JLabel("Blank Lines", JLabel.CENTER));
- this.add(new JLabel("Non-Blank Lines", JLabel.CENTER));
- this.add(tfTotalLines);
- this.add(tfBlankLines);
- this.add(tfNonBlankLines);
- this.add(new JLabel("Only Codes", JLabel.CENTER));
- this.add(new JLabel("Only Comments", JLabel.CENTER));
- this.add(new JLabel("CodeWithComments", JLabel.CENTER));
- this.add(tfCodeLines);
- this.add(tfCommentLines);
- this.add(tfCodeWithCommentLines);
- tfTotalLines.setEditable(false);
- tfBlankLines.setEditable(false);
- tfNonBlankLines.setEditable(false);
- tfCodeLines.setEditable(false);
- tfCommentLines.setEditable(false);
- tfCodeWithCommentLines.setEditable(false);
- tfTotalLines.setHorizontalAlignment(JTextField.CENTER);
- tfBlankLines.setHorizontalAlignment(JTextField.CENTER);
- tfNonBlankLines.setHorizontalAlignment(JTextField.CENTER);
- tfCodeLines.setHorizontalAlignment(JTextField.CENTER);
- tfCommentLines.setHorizontalAlignment(JTextField.CENTER);
- tfCodeWithCommentLines.setHorizontalAlignment(JTextField.CENTER);
- }
- });
- this.add(new JLabel("要统计的扩展名:"));
- this.add(tfExts);
- JButton btn = new JButton("打开目录");
- this.add(btn);
- btn.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- JFileChooser fileChooser = new JFileChooser();
- fileChooser.setApproveButtonText("统计");
- fileChooser.setDialogTitle("选择要统计行数的目录");
- fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- int choose = fileChooser.showOpenDialog(((Component)e.getSource()).getParent());
- if (choose == JFileChooser.APPROVE_OPTION){
- File file = fileChooser.getSelectedFile();
- LineCounter counter = new LineCounter();
- counter.setFileExts(tfExts.getText().split(", "));
- counter.count(file.getAbsolutePath());
- tfTotalLines.setText(String.valueOf(counter.getTotalLines()));
- tfBlankLines.setText(String.valueOf(counter.getBlankLines()));
- tfNonBlankLines.setText(String.valueOf(counter.getNonBlankLines()));
- tfCodeLines.setText(String.valueOf(counter.getCodeLines()));
- tfCommentLines.setText(String.valueOf(counter.getCommentLines()));
- tfCodeWithCommentLines.setText(String.valueOf(counter.getCodeWithCommentsLines()));
- }
- }
- });
- }
- /**
- * @param args
- */
- public static void main(String[] args) {
- new LineCounterUI();
- }
- }