zoukankan      html  css  js  c++  java
  • 软工个人项目WC(Java实现)

    WC个人项目(JAVA实现)

    一、Github地址:https://github.com/GordonKowk/WC_Item


    二、PSP表格

    PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
    Planning 计划 30 36
    · Estimate · 估计这个任务需要多少时间 30 30
    Development 开发 960 784
    · Analysis · 需求分析  50 50
    · Design Spec · 生成设计文档 30 43
    · Design Review · 设计复审  20 20
    · Coding Standard · 代码规范 20 20
    · Design · 具体设计 80 60
    · Coding · 具体编码 750 681
    · Code Review · 代码复审 30 30
    · Test · 测试(自我测试,修改代码,提交修改) 180 180
    Reporting 报告 60 85
    · Test Report · 测试报告 60 60
    · Size Measurement · 计算工作量 20 20
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 40 40
    合计   2360 2159

    三、遇到的问题&解题思路:

    1)一开始着手这个项目的时候挺苦恼的,因为我第一次用cmd去运行一个java文件(妈呀,我才发现调控台原来是命令行),但是学习过后也是比较简单的。项目做出了多个java文件,就在命令行里编译多个,最后选出主类去运行。因为我用的是MyEclipse,写出的java自带包,必须去掉包后才能够让cmd运行时不报错。

    2)不论是什么功能,先写入一个switch去判断每一个Processro,从简单的入手,基础功能-c,-w,-l,-a的功能都是我们课堂接触过的,如何把文件内容送入缓冲区也是学过的。能说不同的,是-a统计里对注释行的判断,“\”可以通过判断一行文字内是否存在得知,“/*……*/”,则可以先判断注释首部,让判断处于注释状态,再去寻找末尾。在功能判断的代码中因为单独判断一个元素(第一个元素arr[0]通常是“-c”“-w”之类的,这种不是路径的字符串无法给予file)会报错,我便把“-x”图形界面和“退出”两个判断放出switch。

    3)递归调用。统计当前文件夹下符合的要求的文件,包括子文件。对于当前目录,由于arr[length-1]是最后一个元素,也就是你本来想要统计的文件路径。通过String类的substring(),LastIndexOf()方法分开父级文件夹名字和文件后缀名,用file.isFile()和file.isDirectory()等方法去判统计当前目录下的文件夹数量和名字、相同后缀名的文件数量和名字,这些数据被放在不同的字符串数组里面。对于子文件,我创建一个递归方法sonProcessor(),接受的数据时之前统计好的文件夹名字和统计文件的后缀名。相同的,递归方法对文件夹的数组里每一个文件夹路劲再一次进行统计,如果有,继续调用自己(这样做会让输出结果从最里面的文件夹开始统计),直到没有文件。最后是输出数据问题,我之前只写了一个文本输入流,却给了四个功能方法去调用,导致的结果是统计出来的数据会一直累计,一个3552字数的文件,在第二次统计达到8000多,最后我是分开了四个不同的文本输送流才解决了问题(我不知道是否有更好的方法,因为这么多文本输送肯定是不现实的)。

    4)通配符的问题。我一开始会比较考虑要不要去写“正则表达式”(正则表达式其实比switch更具有判断性),但是做好了递归功能后我发现可以用String类的substring(),LastIndexOf()方法,对于通用符“*”,截取文件路径最后一次出现“”和“.”中间的地方,就是“*”通用符,因此在switch前可以加上一次判断,如果是“*”出现了,直接调用递归。

    5)最后是图形界面,个人感觉是比较简单的,我设计了带有六个按钮和带有一个文本域的界面,分别对应-c,-w,-l,-a,综合和退出的功能,我先定义一个整数Type,功能按钮都给予能调用FileChooser的监听器,并且每个按钮都会改变Type的值,输出对应的统计内容。


    四、设计与实现

    主要分类只有三个,主类Wc,功能类Function_Directory以及界面类GUI_Frame。

    主要调用流程:

    五、测试运行

    测试文件包括:三个java文件,一个txt文件,两个不相关文件夹、嵌套目录(文件内带有三个java文件,一个子文件夹又带有三个java文件)

    Wc.java在CMD里面的运行界面:

     

    基础功能与扩展功能-a:

     

    递归调用-s与通用符“*”:

     图形界面:

    Wc.java

    复制代码
    static boolean TRUE_OR_NOT = true;
     
     public static void main(String[] args){
      System.out.println("*-------------------WC统计-------------------*");
      System.out.println("基础功能说明:");
      System.out.println("  统计字符数:-c [您要查找的文件路径]");
      System.out.println("  统计词数:  -w [您要查找的文件路径]");
      System.out.println("  统计行数:  -l [您要查找的文件路径]");
      System.out.println("");
      System.out.println("拓展功能说明:");
      System.out.println("  统计空行、代码行、注释行:    -a [您要查找的文件路径]");
      System.out.println("  递归处理:   -s [您要查找的文件路径]");
      System.out.println("");
      System.out.println("高级功能说明:");
      System.out.println("  图形化界面:-x");
      System.out.println("");
      System.out.println("若想退出程序请输入:退出");
      System.out.println("*--------------------------------------------*");
      System.out.println("请输入指令:"); 
      while(TRUE_OR_NOT){
       Scanner command = new Scanner(System.in);
       String[] arr = command.nextLine().split("\s");
       int len = arr.length;
       Function_Directory FD = new Function_Directory();
       FD.commandProcessor(arr,len,0,arr[arr.length-1]); //把数据都交给FD对象里面
      }
     }
    复制代码

    GUI_Frame.java

    复制代码
    private static final long serialVersionUID = 1L;
     
     Toolkit          kit        = Toolkit.getDefaultToolkit();
     Dimension         screenSize   = kit.getScreenSize();
     static  JTextArea   textArea     = new JTextArea();
     private JPanel      chooseBar    = new JPanel();
     private JButton     count_c      = new JButton("字符数");
     private JButton     count_w     = new JButton("词数");
     private JButton     count_l      = new JButton("行数");
     private JButton     count_a     = new JButton("拓展功能");
     private JButton     count_all    = new JButton("总结");
     private JButton     count_close  = new JButton("关闭");
     private Font     buttonFont     = new Font("宋体",Font.BOLD,25);
     int       charNum        = 0;
     int       wordNum         = 0;
     int       lineNum        = 0;
     int       blankLineNum      = 0;
     int       codeLineNum       = 0;
     int       annotationLineNum  = 0;
     int       Type    = 0;
     ArrayList<Integer>    resultList    = null;
     
     
     GUI_Frame(){
      setTitle("WC统计");
      setSize(2*screenSize.width/4,3*screenSize.height/4);   
      setLocation(2*screenSize.width/4,screenSize.height/8);
      initEventListeners();     
      add(chooseBar,BorderLayout.NORTH);
      initChooseBar();
         initTextArea();
     }
     
     private void initChooseBar(){            //顶部选项栏设置
      chooseBar.add(count_c);
      chooseBar.add(count_w);
      chooseBar.add(count_l);
      chooseBar.add(count_a);
      chooseBar.add(count_all);
      chooseBar.add(count_close);
            count_c.setFont(buttonFont);
            count_w.setFont(buttonFont);
            count_l.setFont(buttonFont);
            count_a.setFont(buttonFont);
            count_all.setFont(buttonFont);
            count_close.setFont(buttonFont);
        }
     
     private void initTextArea(){
            textArea.setFont(new Font("宋体", Font.PLAIN, 30));
            textArea.setMargin(new Insets(3,10,3,10));
            textArea.setLineWrap(true);
            textArea.setDragEnabled(true);
            JScrollPane panel = new JScrollPane(textArea,
                    ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                    ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            getContentPane().add(panel, BorderLayout.CENTER);
        }
     
     private void initEventListeners(){
      count_c.addActionListener(  this::countC );
      count_w.addActionListener(  this::countW );
      count_l.addActionListener(  this::countL );
      count_a.addActionListener(  this::countA );
      count_all.addActionListener( this::countAll );
      count_close.addActionListener( this::countClose);
     }
     
     private void countC(ActionEvent event){
      Type = 1;
      CountStart();
     }
     private void countW(ActionEvent event){
      Type = 2;
      CountStart();
     }
     private void countL(ActionEvent event){
      Type = 3;
      CountStart();
     }
     private void countA(ActionEvent event){
      Type = 4;
      CountStart();
     }
     private void countAll(ActionEvent event){
      Type = 5;
      CountStart();
     }
     private void countClose(ActionEvent event){
      Type = 0;
      System.exit(0);
     }
     
     public void CountStart(){
      JFileChooser chooser = new JFileChooser();
            chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
            chooser.showDialog(new JLabel(), "选择要统计的文件");
            File file = chooser.getSelectedFile();
            try{
       String encoding = "GBK";
       InputStreamReader readFile = new InputStreamReader(new FileInputStream(file),encoding);
       BufferedReader fileContent = new BufferedReader(readFile);
       switch(Type){
       case 1:
        charNum = Function_Directory.charsCounter(fileContent);
        textArea.append(file+": "+"字符数:" + charNum + " ");
        break;
       case 2:
        wordNum = Function_Directory.wordsCounter(fileContent);
        textArea.append(file+": 词数:" + wordNum+" ");
        break;
       case 3:
        lineNum = Function_Directory.linesCounter(fileContent);
        textArea.append(file+": 行数:" + lineNum+" ");
        break;
       case 4:
        resultList = Function_Directory.Expand_Count(fileContent);
        blankLineNum = resultList.get(0);
        codeLineNum = resultList.get(1);
        annotationLineNum = resultList.get(2);
        textArea.append(file+": 空行数:" + blankLineNum + " 代码行数:"
          + codeLineNum + " 注释行数" + annotationLineNum+" ");
        break;
       case 5:
        charNum = Function_Directory.charsCounter(fileContent);
        wordNum = Function_Directory.wordsCounter(fileContent);
        lineNum = Function_Directory.linesCounter(fileContent);
        resultList = Function_Directory.Expand_Count(fileContent);
        blankLineNum = resultList.get(0);
        codeLineNum = resultList.get(1);
        annotationLineNum = resultList.get(2);
        textArea.append(file+": "+"字符数:" + charNum + " 词数:"
          + wordNum + " 行数:" + lineNum + " 空行数:" + blankLineNum + " 代码行数:"
          + codeLineNum + " 注释行数" + annotationLineNum+" "); 
       }   
      }catch(IOException e){
        System.out.println("文件路径错误或者文件不支持喔~");
        e.printStackTrace();
      }
     }
     
     public static void main(String[] args) {
      GUI_Frame GF = new GUI_Frame();
      GF.setVisible(true);
     }
    复制代码

    Function_Directory.java

    复制代码
    public class Function_Directory {
     public void commandProcessor(String[] arr,int len,int start,String fileName){
      if(arr[0].equals("-x")){      //由于只输入一个元素会报错,“-x”和“退出”先提前判断
       GUI_Frame GF = new GUI_Frame();    //一个图形化界面
       GF.setVisible(true);
      } else if(arr[0].equals("退出")) { Wc.TRUE_OR_NOT = false;
      } else{
       try{
        for(int i = start;i < len-1||i == 0;i++){
         String fileUrl = arr[arr.length-1].substring(arr[arr.length-1].lastIndexOf("\")+1,arr[arr.length-1].lastIndexOf("."));
         System.out.println(fileUrl);
         if(fileUrl.equals("*")) recursiveProcessor(arr); //判断通用符号“*”
         else{
          String encoding = "GBK";
          File file = new File(fileName);
          InputStreamReader readFile = new InputStreamReader(new FileInputStream(file),encoding);
          BufferedReader fileContent = new BufferedReader(readFile);   
         switch(arr[i]){
          case "-c":
           charsCounter(fileContent);
           break;
          case "-w":
           wordsCounter(fileContent);
           break;
          case "-l":
           linesCounter(fileContent);
           break;
          case "-a":
           Expand_Count(fileContent);
           break;
          case "-s":
           recursiveProcessor(arr);
           break;
          default:break;
         }
        }}
       }catch(Exception e){
        System.out.println(arr[0]+"不是功能指令喔~,看看是不是哪里输入错误了。");
        e.printStackTrace();
       }
      }
     }
     
     static int charsCounter(BufferedReader fileContent) throws IOException{
      String  lineCount  = null;
      int  charNum  = 0;
      while((lineCount  = fileContent.readLine()) != null){
       lineCount   = lineCount.trim();
       for(int i = 0;i < lineCount.length();i++){
        char ch  = lineCount.charAt(i);
        if(ch != ' ' && ch != ' ' && ch != ' ')
         charNum++;
       }
      }
      System.out.println("字符数:" + charNum);
      return charNum;
     }
     
     static int wordsCounter(BufferedReader fileContent) throws IOException{
      String  REGEX   = "[a-zA-Z]+\b";  //判断词的正则表达式
      String  lineCount  = null;
      int  wordNum  = 0;
      Pattern pattern  = Pattern.compile(REGEX);
      while((lineCount = fileContent.readLine()) != null){
        lineCount  = lineCount.trim();
       Matcher matcher = pattern.matcher(lineCount);
       while(matcher.find()){
        wordNum++;
       }
      }
      System.out.println("词数:" + wordNum);
      return wordNum;
     }
     
     static int linesCounter(BufferedReader fileContent) throws IOException{
      int  lineNum  = 0;
      String  lineCount  = null;
      while((lineCount = fileContent.readLine()) != null){ lineNum++; }
      System.out.println("行数:" + lineNum);
      return  lineNum;
     }
     
     static ArrayList<Integer> Expand_Count(BufferedReader fileContent)throws IOException{
      String  lineCount  = null;
      ArrayList<Integer>  resultList   = new ArrayList<Integer>();
      boolean    isComment   = false;
      int  codeLineNum   = 0;
      int  blankLineNum   = 0;
      int  annotationLineNum  = 0;
      while((lineCount = fileContent.readLine()) != null){   //对注释行的判断
       if(lineCount.contains("/*")){
        annotationLineNum++;
        isComment = true;
       } else if(isComment){
        annotationLineNum++;
        if(lineCount.contains("*/")){ isComment = false; }
       } else if(lineCount.contains("//")){
        annotationLineNum++;
       } else if(lineCount.trim().length() > 1){
        codeLineNum++;
       } else{
        blankLineNum++;
       }
      } 
      System.out.println("空行数:" + blankLineNum);
      System.out.println("代码行数:" + codeLineNum);
      System.out.println("注释行数:" + annotationLineNum);
      resultList.add(blankLineNum);
      resultList.add(codeLineNum);
      resultList.add(annotationLineNum);
      return resultList;
     }
     
     public void recursiveProcessor(String[] arr) throws IOException{
      int   LA    = arr.length;
      int   n    = 0;
      String   fileUrl   = arr[LA-1].substring(0,arr[LA-1].lastIndexOf("\")); //找到文件路径最先出现“”的位置
      String   fileEnd   = arr[LA-1].substring(arr[LA-1].lastIndexOf("."));  //找到文件路径最先出现“.”的位置
            List<File>  fileList   = new ArrayList<File>();
            File   file    = new File(fileUrl);
            File[]   files    = file.listFiles();
            String[]    names   = file.list();
            String[] CompletNames  = null;
            for (File f : files) {
             if (f.isDirectory()){ n++;    }
            }
            CompletNames    = new String[n];
            n       = 0;
            if (files == null) {}
            for (File f : files) {
                if (f.isFile()&&f.getName().endsWith(fileEnd)) {  fileList.add(f); }
                if (f.isDirectory()){
                 CompletNames[n] = arr[LA-1].substring(0,arr[LA-1].lastIndexOf("\"))+"\"+f.getName();
                 System.out.println(CompletNames[n]);
                 n++;
                }
            }
            for (File f1 : fileList) {
             System.out.println(fileUrl+"\"+f1.getName());
       String encoding = "GBK";
       InputStreamReader rC = new InputStreamReader(new FileInputStream(f1),encoding);
       InputStreamReader rW = new InputStreamReader(new FileInputStream(f1),encoding);
       InputStreamReader rL = new InputStreamReader(new FileInputStream(f1),encoding);
       InputStreamReader rA = new InputStreamReader(new FileInputStream(f1),encoding);
        BufferedReader C = new BufferedReader(rC);
        BufferedReader W = new BufferedReader(rW);
        BufferedReader L = new BufferedReader(rL);
        BufferedReader A = new BufferedReader(rA);
         charsCounter(C);
         wordsCounter(W);
         linesCounter(L);
         Expand_Count(A);
       C.close();        //我试过只写一个文本输入流,统计结果会累积,数据错误
       W.close();        //由于写入太多输入流,希望想找到更好的办法
       L.close();
       A.close();       
            }
      System.out.println("*-----------------------------*");
      if (CompletNames!=null) sonProcessor(CompletNames,fileEnd); 
     }
     private void sonProcessor(String[] Names,String End) throws IOException { 
      String[]     N     = Names;    //寻找子文件,并把子文件里面符合要求的文件统计出来
      int    LengthA   = N.length;    //这里我运用了递归,但是发现是先递归到最里层才开始统计
      for(int i=0;i<Names.length;i++){
       int   n    = 0;
       String   fileUrl   = N[i];
       String   fileEnd   = End;
       List<File>  fileList   = new ArrayList<File>();
             File   file    = new File(fileUrl);
             File[]   files    = file.listFiles();
             String[]    names   = file.list();
             String[] CompletNames  = null;
             for (File f : files) {
              if (f.isDirectory()){ n++; }
             }
             CompletNames    = new String[n];
             n       =0; 
             if (files == null) {}
             for (File f : files) {
                 if (f.isFile()&&f.getName().endsWith(fileEnd)) {  fileList.add(f); }
                 if (f.isDirectory()){
                  CompletNames[n]  = N[i]+"\"+f.getName();
                  System.out.println(CompletNames[n]);
                  n++;
                 }
             }
             if (CompletNames!=null)  sonProcessor(CompletNames,fileEnd);
             for (File f1 : fileList) {
        System.out.println(N[i]+"\"+f1.getName());
        String encoding = "GBK";
        InputStreamReader rC = new InputStreamReader(new FileInputStream(f1),encoding);
        InputStreamReader rW = new InputStreamReader(new FileInputStream(f1),encoding);
        InputStreamReader rL = new InputStreamReader(new FileInputStream(f1),encoding);
        InputStreamReader rA = new InputStreamReader(new FileInputStream(f1),encoding);
         BufferedReader C = new BufferedReader(rC);
         BufferedReader W = new BufferedReader(rW);
         BufferedReader L = new BufferedReader(rL);
         BufferedReader A = new BufferedReader(rA);
          charsCounter(C);
          wordsCounter(W);
          linesCounter(L);
          Expand_Count(A);
        C.close();
        W.close();
        L.close();
        A.close();
        System.out.println("*-----------------------------*");
             }
      }
     }
    复制代码

     六、项目总结:

       这次项目让我感受最深的是做这个项目的计划,先给自己一个规划,做出要想做的框架流程,想好自己应该干嘛,用多少时间,应该怎么去测试,以前的课设我是没有注意到这些的,这也让我看到做一个项目的严谨性。之前的java程序我都是通过设计图形化界面去运行的,没有像这次在命令行里面运行,学会了如何在命令行编译与运行java文件。递归调用的实现也是我印象最深刻的,文件夹和文件的路径由于循环让我自己都搞晕了,不断调试,不断找准切分位置,不断有报错,文件夹数组长度不能过长,路径不能错误,有时数据会卡住循环进行。递归的实现是我用时最多的部分。但是因为想去搞懂,从网上找资料,询问同学,学到不少,也能想出适合自己的方法。现在是个人项目,我期待在后面的项目能收获更多。

  • 相关阅读:
    C语言 sprintf 函数 C语言零基础入门教程
    C语言 printf 函数 C语言零基础入门教程
    C语言 文件读写 fgets 函数 C语言零基础入门教程
    C语言 文件读写 fputs 函数 C语言零基础入门教程
    C语言 fprintf 函数 C语言零基础入门教程
    C语言 文件读写 fgetc 函数 C语言零基础入门教程
    C语言 文件读写 fputc 函数 C语言零基础入门教程
    C语言 strlen 函数 C语言零基础入门教程
    Brad Abrams关于Naming Conventions的演讲中涉及到的生词集解
    适配器模式
  • 原文地址:https://www.cnblogs.com/GordonKowk/p/11570256.html
Copyright © 2011-2022 走看看