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文件。递归调用的实现也是我印象最深刻的,文件夹和文件的路径由于循环让我自己都搞晕了,不断调试,不断找准切分位置,不断有报错,文件夹数组长度不能过长,路径不能错误,有时数据会卡住循环进行。递归的实现是我用时最多的部分。但是因为想去搞懂,从网上找资料,询问同学,学到不少,也能想出适合自己的方法。现在是个人项目,我期待在后面的项目能收获更多。

  • 相关阅读:
    什么是反向代理,反向代理有什么好处?
    动态的favicons
    管理emacs dotemacs文件
    自己的部分小软件合计 2000 2013(很久没有更新了)
    经典CSS 横向导航菜单【下载】
    Web 调试,兼容浏览器的在线调试(系列)
    sql server 执行大脚本时报警告没有足够的内存继续执行程序
    c#对接顺丰图片文件
    Sql Server行转列 动态拼接sql
    centos6.2更新yum源
  • 原文地址:https://www.cnblogs.com/GordonKowk/p/11570256.html
Copyright © 2011-2022 走看看