个人项目(wc.exe)
阅读原文时间:2023年07月09日阅读:1

·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 fileNameList = new ArrayList<>();//文件名列表
4 List 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

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表格前后对比,发现我还需要学习的知识点还很多,缺乏项目经验。