个人项目(wc.exe)

一、项目在GitHub上的地址:

·https://github.com/DawsonHuang/Word_Count

二、项目描述:

·项目名:WordCount(以下简称WC或项目)

·项目简述:实现一个统计程序wc.exe,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他

        扩展功能,并能够快速地处理多个文件

·项目具体需求:

  ·程序处理用户需求的模式为:

    ·wc.exe [parameter] [file_name]    //[file_name]: 文件或目录名,可以处理一般通配符。

   ·基本功能列表: 【已实现】

    ·wc.exe -c file.c     //返回文件 file.c 的字符数

    ·wc.exe -w file.c     //返回文件 file.c 的词的数目  

    ·wc.exe -l file.c     //返回文件 file.c 的行数

   ·扩展功能: 【已实现】

      ·-s   递归处理目录下符合条件的文件。

      ·-a   返回更复杂的数据(代码行 / 空行 / 注释行)。

    ·注:

      ·①空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,

           例如“{”。

      ·②代码行:本行包括多于一个字符的代码。

      ·③注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面

            加注释:} //注释,在这种情况下,这一行属于注释行。    

      ·需求举例:

      ·wc.exe -s -a *.c  //返回当前目录及子目录中所有*.c 文件的代码行、空行、注释行数。 

  ·高级功能:  【已实现】

     · -x 参数:这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选

           取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

三、设计思路:

  ·根据输入的需要处理的文件地址,通过IO流来进行文件读取,然后再根据键入的命令类型,调用不同的方法

   处理,运用readLine()方法对文件进行按行读取,通过split()方法计算出字符数、单词数、行数;再通过正

   则表达式,matches()方法识别统计空行、注释行、代码行;将基本功能封装在BasicOperation方法中,统计

   特殊行的功能封装在SpecialLine方法中,递归查找文件的方法为RecrusiveOperation

  ·编程语言:Java

  ·功能代码块:

    ·main()方法:接收输入、调用功能块

    ·基本功能:BasicOperation(String order,String[] input){....}

    ·查找特殊行:SpecialLine(String Path){....}

    ·递归查找文件:RecrusiveOperation(String endwith_name,String[] input,String path){....}

  ·流程图:

  

四、代码分析:

·主函数:

 1 /**
 2  * 本程序支持的命令行格式:
 3  * 1、wc.exe -c 文件路径
 4  * 2、wc.exe -w 文件路径
 5  * 3、wc.exe -l 文件路径
 6  * 4、wc.exe -a 文件路径
 7  * 5、wc.exe -s -a 文件路径
 8  * 6、wc.exe -x 文件路径
 9  */
10 public static void main(String[] args) throws Exception{
11         Scanner in = new Scanner(System.in);
12         System.out.println("请注意输入格式 'wc.exe [order] [file_name]:");
13         String[] input = in.nextLine().split(" ");
14         System.out.println(Arrays.toString(input));
15         if("-s".equals(input[1])) {     //输入类型是 wc.exe -s ....
16             System.out.println("请输入你要在以上目录中递归查找的文件的后缀:");
17             String endwith_name = in.nextLine();  //后缀名
18             String path;    //输入的要递归查询的目录
19             path = input[3];    //文件夹路径    
20             RecrusiveOperation(endwith_name,input,path);
21         }else if("-a".equals(input[1])){  //输入类型是 wc.exe -a ....
22             SpecialLine(input[2]);
23         }else{
24             String order = input[1];
25             BasicOperation(order,input);
26         }
27     }

·基本需求:

 1 //基本功能实现(-c / -w / -l)
 2     public static void BasicOperation(String order,String[] input) throws Exception{
 3         int Count_Char=0;
 4         int Count_Word=0;
 5         int Count_Line=0;
 6         FileInputStream file = new FileInputStream(input[2]);
 7         InputStreamReader is = new InputStreamReader(file);
 8         BufferedReader br = new BufferedReader(is);
 9         String s;
10         switch(order) {
11             //计算字符数
12             case "-c":
13                 while((s=br.readLine())!=null){
14                     Count_Char += s.length();
15                 }
16                 System.out.println("字符数:"+Count_Char);
17                 break;
18             //计算单词数
19             case "-w":
20                 while((s=br.readLine())!=null){
21                     Count_Word += s.split(" ").length;
22                 }
23                 System.out.println("单词数:"+Count_Word);
24                 break;
25             //计算行数
26             case "-l":
27                 while(br.readLine()!=null){
28                     Count_Line++;
29                 }
30                 System.out.println("行数:"+Count_Line);
31                 break;
32             default:
33                 System.out.println("输入错误!");
34         }
35     }

·递归查找文件

 1     //扩展功能实现:-s 递归处理目录下符合条件的文件
 2     public static void RecrusiveOperation(String endwith_name,String[] input,String path) throws Exception{
 3         List<String> fileNameList = new ArrayList<>();//文件名列表
 4         List<String> filePathList = new ArrayList<>();
 5         File f = new File(path);
 6         if (!f.exists()) { //路径不存在
 7             System.out.println("该路径不存在!");
 8         }else{
 9             if(f.isFile()){ //路径为文件
10                 if(f.getName().indexOf(endwith_name)!=-1) {
11                     fileNameList.add(f.getName());
12                     filePathList.add(f.getAbsolutePath());
13                 }
14             }else if(f.isDirectory()){ //路径为文件夹
15                 File fa[] = f.listFiles();    //获取改目录下所有文件和目录的绝对路径
16                 System.out.println(Arrays.toString(fa));
17                 for (int i = 0; i < fa.length; i++) {
18                     File fs = fa[i];
19                     if(fs.isFile()){
20                         if(fs.getName().indexOf(endwith_name)!=-1){
21                             fileNameList.add(fs.getName());
22                             filePathList.add(fs.getAbsolutePath());
23                         }
24                     }else if(fs.isDirectory()) {
25                         RecrusiveOperation(endwith_name, input, fs.getAbsolutePath());
26                     }
27                 }
28             }
29         }
30         for(int i = 0;i < filePathList.size();i++){
31             //System.out.println(fileNameList.get(i));
32             System.out.println(filePathList.get(i)+":");
33             switch(input[2]) {
34                 case "-c":
35                     BasicOperation("-c", input);    break;
36                 case "-w":
37                     BasicOperation("-w", input);    break;
38                 case "-l":
39                     BasicOperation("-l", input);    break;
40                 case "-a":
41                     SpecialLine(filePathList.get(i));     break;
42             }
43             System.out.println();
44         }
45     }

·查找特殊行

 1 //扩展功能实现:-a 返回更复杂的数据(代码行/空行/注释行)
 2     public static void SpecialLine(String path) throws Exception {
 3         int BlankLine = 0;      //空行数
 4         int AnnotationLine = 0;     //注释行数
 5         int CodeLine = 0;       //代码行数
 6         FileInputStream file = new FileInputStream(path);
 7         InputStreamReader is = new InputStreamReader(file);
 8         BufferedReader br = new BufferedReader(is);
 9         String s;
10         //正则表达式表示空行
11         String RegexBlankLine = "(\\{|\\})?\\s*";   //空行
12         //正则表达式表示单行注释
13         String RegexAnnotation = "\\s*(\\{|\\})?\\s*//.*";    //单行注释符‘//14         //正则表达式表示多行注释
15         String RegexAnnotationStart = "\\s*(\\{||\\})?/\\*.*";   //多行注释起始符‘/*’
16         String RegexAnnotationEnd = ".*\\*/";       //多行注释结束符‘*/’
17         while ((s = br.readLine()) != null) {
18             if (s.matches(RegexBlankLine)) {
19                 BlankLine++;
20             } else if (s.matches(RegexAnnotation)) {
21                 AnnotationLine++;
22             } else if (s.matches(RegexAnnotationStart)) {
23                 do {
24                     AnnotationLine++;
25                     s = br.readLine();
26                 } while (!s.matches(RegexAnnotationEnd));
27                 AnnotationLine++;     //多行注释结束符所在行也应加上
28             } else {
29                 CodeLine++;
30             }
31         }
32         System.out.println("空白行:" + BlankLine + " 行.");
33         System.out.println("注释行:" + AnnotationLine + " 行.");
34         System.out.println("代码行:" + CodeLine + " 行.");
35     }
       public static void _x(){
new FileFrame();
}

·-x

  1 package JFrame;
  2 
  3 import com.HDH.WC;
  4 
  5 import java.awt.*;
  6 import java.awt.event.ActionEvent;
  7 import java.awt.event.ActionListener;
  8 import java.io.File;
  9 import javax.swing.*;
 10 
 11 /**
 12  * GUI
 13  * @author Dawson_Huang
 14  * @Date 2020/3/14 - 9:27
 15  */
 16 
 17 public class FileFrame implements ActionListener {
 18     JFrame frame = new JFrame("文件选择");// 框架布局
 19     JTabbedPane tabPane = new JTabbedPane();// 选项卡布局
 20     Container con = new Container();
 21     JLabel label1 = new JLabel("文件目录");
 22     JTextField text1 = new JTextField();// TextField 目录的路径
 23     JButton button1 = new JButton("选择");// 选择
 24     JFileChooser jfc = new JFileChooser();// 文件选择器
 25     JLabel label2 = new JLabel("选择命令");
 26     JCheckBox jCheckBoxC = new JCheckBox("-c");
 27     JCheckBox jCheckBoxW = new JCheckBox("-w");
 28     JCheckBox jCheckBoxL = new JCheckBox("-l");
 29     JCheckBox jCheckBoxA = new JCheckBox("-a");
 30     JButton button2 = new JButton("确定");//
 31 
 32     public static void main(String[] args) {
 33         new FileFrame();
 34     }
 35 
 36     public FileFrame() {
 37         jfc.setCurrentDirectory(new File("d://"));   // 文件选择器的初始目录为d盘
 38         double lx = Toolkit.getDefaultToolkit().getScreenSize().getWidth();  // 显示屏幕的宽度
 39         double ly = Toolkit.getDefaultToolkit().getScreenSize().getHeight(); // 显示屏幕的高度
 40         frame.setLocation(new Point((int) (lx / 2) - 150, (int) (ly / 2) - 150)); // 窗口出现的位置
 41         frame.setSize(500, 360);// 设定窗口大小
 42         frame.setContentPane(tabPane);// 设置布局
 43         label1.setBounds(10, 10, 70, 20);
 44         text1.setBounds(75, 10, 120, 20);
 45         button1.setBounds(210, 10, 50, 20);
 46         label2.setBounds(10, 60, 70, 20);
 47         button2.setBounds(240, 60, 60, 20);
 48         jCheckBoxC.setBounds(80, 60, 40, 20);
 49         jCheckBoxW.setBounds(120, 60, 40, 20);
 50         jCheckBoxL.setBounds(140, 60, 40, 20);
 51         jCheckBoxA.setBounds(180, 60, 40, 20);
 52         button1.addActionListener(this); // 添加事件处理
 53         button2.addActionListener(this); // 添加事件处理
 54         con.add(label1);
 55         con.add(text1);
 56         con.add(button1);
 57         con.add(label2);
 58         con.add(jCheckBoxC);
 59         con.add(jCheckBoxW);
 60         con.add(jCheckBoxL);
 61         con.add(jCheckBoxA);
 62         con.add(button2);
 63         frame.setVisible(true);// 窗口可见
 64         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 使能关闭窗口,结束程序
 65         tabPane.add("1面板", con);// 添加布局1
 66     }
 67     
 68     public String path;
 69     public String order;
 70     /**
 71      * 时间监听的方法
 72      */
 73     public void actionPerformed(ActionEvent e) {
 74         if (e.getSource().equals(button1)) { // 判断触发方法的按钮是哪个
 75             int state = jfc.showOpenDialog(null);// 此句是打开文件选择器界面的触发语句
 76             if (state == 1) {
 77                 return;
 78             } else {
 79                 File f = jfc.getSelectedFile();// f为选择到的目录
 80                 text1.setText(f.getAbsolutePath());
 81                 path = f.getAbsolutePath();
 82             }
 83         }
 84         if (e.getSource().equals(button2)) {
 85             JCheckBox[] jcbs = {jCheckBoxA, jCheckBoxC, jCheckBoxL, jCheckBoxW};
 86             for (JCheckBox j : jcbs) {
 87                 if (j.isSelected()) {
 88                     order = j.getText();
 89                     switch(order) {
 90                         case "-c":
 91                             try {
 92                                 WC.BasicOperation("-c",path);
 93                             } catch (Exception ex) {
 94                                 ex.printStackTrace();
 95                             }
 96                             break;
 97                         case "-w":
 98                             try {
 99                                 WC.BasicOperation("-c",path);
100                             } catch (Exception ex) {
101                                 ex.printStackTrace();
102                             }
103                             break;
104                         case "-l":
105                             try {
106                                 WC.BasicOperation("-c",path);
107                             } catch (Exception ex) {
108                                 ex.printStackTrace();
109                             }
110                             break;
111                         case "-a":
112                             try {
113                                 WC.SpecialLine(path);
114                             } catch (Exception ex) {
115                                 ex.printStackTrace();
116                             }
117                             break;
118                     }
119                 }
120             }
121         }
122     }
123 }

 

五、测试运行:

·文件目录:

 

·测试结果:

  ·命令"-c":

     

   ·命令"-w":

     

   ·命令"-l":

   

   ·命令"-s -a":

   

 

  ·命令"-x":

   

 

 

             

 

         

六、PSP2.1表格:

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

25

20

· Estimate

· 估计这个任务需要多少时间

60

60

Development

开发

180

240

· Analysis

· 需求分析 (包括学习新技术)

20

20

· Design Spec

· 生成设计文档

30

30

· Design Review

· 设计复审 (和同事审核设计文档)

20

20

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

10

10

· Design

· 具体设计

60

60

· Coding

· 具体编码

240

360

· Code Review

· 代码复审

25

30

· Test

· 测试(自我测试,修改代码,提交修改)

40

60

Reporting

报告

35

40

· Test Report

· 测试报告

20

20

· Size Measurement

· 计算工作量

15

25

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

20

30

合计

 

800

1025

七、遇到的困难及解决方法:

   不知如何表示空行、注释行、代码行,通过百度、CSDN学习了正则表达式,问题已解决。

八、项目小结:

   通过这次练习,我对软件工程有了进一步的了解,通过PSP表格前后对比,发现我还需要学习的知识点还很多,缺乏项目经验。

posted @ 2020-03-15 13:37  Dawson_Huang  阅读(214)  评论(0编辑  收藏  举报