Java設計一個統計文件的字符數等信息的程序並進行測試


 

‘’github鏈接:https://github.com/coolzero2/softwaretest.git

 

補充說明

關於下面貼代碼的時候第6.3條,函數傳入的參數是一個動態數組arraylist。實際上,這是因為*在myeclipse中是通配符,在ecl自帶的run configurations中輸入路徑比如“d:/*.txt”,會自動檢索當前路徑下所有符合條件的文件。但是在CMD中則不會自動檢索。如果按照6.3的代碼,寫出的程序打包成exe后是沒辦法正確運行的。但是這也算是學習到了一些知識,此處就不再刪去了。正確的代碼將會在本文的最末貼出。

另外關於指令輸入的順序規定,主要是根據老師給出的白盒測試中的那幾個例子來的,這也應用到了judge的邏輯判定中。最終正確順序:-w,-s,-a,-c,-l,-*  輸入文件 -e 停用詞表 -o 輸出文件

 

 

第一次寫博客,一方面熟悉一下博客的相關操作,另一方面交一下作業。

本程序最大的缺點應該就是全局變量太多了吧(10+個),這樣的程序安全性應該會受到影響;

其次就是代碼有些繁瑣。

要求提交的時間太緊張,先這樣湊合了。以后有時間修改一下。

首先說明各種指令的功能:

-a:統計文件中的代碼行、空行、注釋行;

-c:統計文件中的字符數,不包括換行符;

-w:統計文件中的單詞數;

-l:統計文件的行數;

-e:當使用該指令時,指定停用詞表,統計文件中的單詞數時不再統計停用詞表中的內容。

-s:使用該指令時,指定的輸入文件應該是一個路徑,統計的信息是路徑下所有符合要求的文件的信息;當文件只有一個時,其實看做一個特例(也就是上面所說的單純統計一個文件)。

-o:使用該指令時,指定輸出文件,用來保存統計輸入文件后輸出的信息。

思考的思路

其實也很簡單。這個軟件的功能就是用戶輸入了一組信息,在信息輸入的格式正確的情況下,將會輸出相關信息。編寫這個程序可以分為兩點:1.分析用戶輸入的內容。2.根據分析,執行相應功能。

第2點需要再進行細化。

PSP表格

PSP2.1表格

PSP2.1

PSP階段

預估耗時

(分鍾)

實際耗時

(分鍾)

Planning

計划

 30 10 

· Estimate

· 估計這個任務需要多少時間

 20 10 

Development

開發

 480 500 

· Analysis

· 需求分析 (包括學習新技術)

 40 40 

· Design Spec

· 生成設計文檔

 60 30 

· Design Review

· 設計復審 (和同事審核設計文檔)

 60 30 

· Coding Standard

· 代碼規范 (為目前的開發制定合適的規范)

0 0

· Design

· 具體設計

 50 30 

· Coding

· 具體編碼

 600 500 

· Code Review

· 代碼復審

 60 120 

· Test

· 測試(自我測試,修改代碼,提交修改)

 120 100 

Reporting

報告

 50 120 

· Test Report

· 測試報告

 60 120 

· Size Measurement

· 計算工作量

 5

· Postmortem & Process Improvement Plan

· 事后總結, 並提出過程改進計划

 5
 

合計

 

下面上代碼。

1.判斷用戶輸入的信息

這里是各種指令對應的flag,邏輯關系依照作業要求設置。為true的時候代表實現相應功能。

private static void judge(String str) {
        // TODO Auto-generated method stub
        if(str.equals("-s")&&s_flag==false){
            s_flag=true;
        }
        else if(str.equals("-*")&&star_flag==false){
            star_flag=true;
            c_flag=true;
            w_flag=true;
            l_flag=true;
            a_flag=true;
        }
        else if(str.equals("-a")&&a_flag==false){
            a_flag=true;
        }
        else if(str.equals("-c")&&c_flag==false){
            c_flag=true;
        }
        else if(str.equals("-w")&&w_flag==false){
            w_flag=true;
        }
        else if(str.equals("-l")&&l_flag==false){
            l_flag=true;
        }
        else if(file_flag==false)//還沒有指定輸入文件
        {
            if(s_flag==false){//如果輸入的不是路徑
                file_name+=str;
                txt_name=str;
                file_flag=true;
            }
            else{
                pathname=str;
                path_flag=true;
            }
        }
        else if(str.equals("-e")&&e_flag==false){
            e_flag=true;
        }
        else if(e_flag==true&&file_flag==true&&o_flag==false&&stop_flag==false){//已經有輸入文件且e_flag為真
            stoplist+=str;
            stop_flag=true;
        }
        else if(str.equals("-o")&&o_flag==false){
            o_flag=true;
        }
        else if(o_flag==true&&file_flag==true){//已經有輸入文件且o_flag為真
            output_name+=str;
            all_flag=true;
        }
        else{
            System.out.println("指令錯誤,請重新輸入");
        }
    }

2.統計文件的字符數

換行符不應該統計到字符的總數中,所以此處會去掉。

private static int num_of_char(String filename) {
        // TODO Auto-generated method stub
        File file=new File(filename);
        Reader readfile=null;
        int c_num=0;
        try{
            readfile = new InputStreamReader(new FileInputStream(file));
            int tempchar;
            while ((tempchar=readfile.read()) != -1) {
                if((char)tempchar!='\r'&&(char)tempchar!='\n'){
                    c_num++;
                }
            }
            readfile.close();
        }
        catch(Exception e){
            System.out.println("指定輸入文件不存在");
        }    
        return c_num;
    }

3.統計單詞數

此處需要判斷字符是否是大小寫字母(IsLetter()),實際上是我自己寫的方法,Java中應該有自帶的判斷字母的方法。

3.1不使用停用詞表

private static int num_of_word(String filename){
        File file=new File(filename);
        Reader readfile=null;
        boolean letter_flag=false;
        int w_num=0;
        try{
            readfile = new InputStreamReader(new FileInputStream(file));
            int tempchar;
            while ((tempchar=readfile.read()) != -1) {
                if(IsLetter((char)tempchar)){
                    letter_flag=true;
                }
                else if(letter_flag==true){
                    letter_flag=false;
                    w_num++;
                }                                
            }
            readfile.close();
        }
        catch(Exception e){
            System.out.println("指定輸入文件不存在");
        }    
        return w_num;
    }

3.2使用停用詞表

這里就可以看出來我實際上是把上面的一段加了一些內容而已。先湊合用,為了代碼的簡潔以后還是要修改。

private static int num_of_word_e(String filename) {
        // TODO Auto-generated method stub
        File file=new File(filename);
        File stopfile=new File(stoplist);
        ArrayList<String>stopstr = new ArrayList<String>();
        Reader readfile=null;
        boolean letter_flag=false;
        int w_num=0;
        //讀取停用詞表內容,保存在stopstr中
        try{
            readfile = new InputStreamReader(new FileInputStream(stopfile));
            int tempchar;
            String str="";
            while ((tempchar=readfile.read()) != -1) {
                if(IsLetter((char)tempchar)){
                    letter_flag=true;
                    str+=(char)tempchar;
                }
                else if(letter_flag==true){
                    letter_flag=false;
                    stopstr.add(str);
                    str="";
                }
            }
            readfile.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
        //判斷word數
        try{
            readfile = new InputStreamReader(new FileInputStream(file));
            int tempchar;
            String str="";
            while ((tempchar=readfile.read()) != -1) {
                if(IsLetter((char)tempchar)){
                    letter_flag=true;
                    str+=(char)tempchar;
                }
                else if(letter_flag==true){
                    letter_flag=false;
                    w_num++;
                    if(e_flag==true){
                        for(int i=0;i<stopstr.size();i++){
                            if(str.compareTo(stopstr.get(i))==0){
                                w_num--;
                            }
                        }
                    }
                    str="";
                }                                
            }
            readfile.close();
        }
        catch(Exception e){
            System.out.println("指定輸入文件不存在");
        }    
        return w_num;
    }

4.統計行數

遇到換行符就加一。Windows中的換行符為“\r\n”,這里只使用"\n"。

private static int num_of_line(String filename) {
        // TODO Auto-generated method stub
        File file=new File(filename);
        Reader readfile=null;
        int l_num=1;
        try{
            readfile = new InputStreamReader(new FileInputStream(file));
            int tempchar;
            while ((tempchar=readfile.read()) != -1) {
                if((char)tempchar=='\n'){
                    l_num++;
                }
            }
            readfile.close();
        }
        catch(Exception e){
            System.out.println("指定輸入文件不存在");
        }    
        return l_num;
    }

5.統計文件的代碼行/空行/注釋行

這里的思路是按行讀文件,去除每一行的換行符和空格,獲得的string長度為0就代表空行;一行中如果只有“{/*”、“{//”、“//”、“/*”代表注釋行(這些就是注釋的開頭),直到統計到注釋的末尾;其余的均為代碼行。實際上這里的注釋行的表達形式並不清晰、全面,只是與C語言的注釋方法類似。比如在/*   */的內部又出現//或者/**/就可能會統計錯誤。

private static int [] code_ana(String filename){
        File file=new File(filename);
        int nothing=0;
        int line=0;
        int note=0;
        int code_line=0;
        boolean note_flag=false;
        BufferedReader readfile = null;
        try{
            readfile = new BufferedReader(new FileReader(file));
            String tempString = null;            
            while ((tempString = readfile.readLine()) != null) {
                line++;
                tempString=tempString.replaceAll("\r\n"," ");//去掉所有換行符和空格
                if(note_flag==true){
                    note++;
                    if(tempString.endsWith("*/")){
                        note_flag=false;//代表注釋內容在本行結束
                    }
                }
                if(tempString.equals(" ")||tempString.equals("{")||tempString.equals("}")){
                    nothing++;
                }
                if(tempString.startsWith("//")||tempString.startsWith("{//")){
                    note++;
                }
                if(tempString.startsWith("/*")||tempString.startsWith("{/*")){
                    if(tempString.endsWith("*/")){
                        note++;
                    }
                    else{
                        note++;
                        note_flag=true;//代表注釋的內容在本行還沒結束
                    }
                }
                code_line=line-note-nothing;
            }
            readfile.close();
        }
        catch(Exception e){
            System.out.println("指定輸入文件不存在");
        }
        int []num =new int[3];
        num[0]=code_line;
        num[1]=nothing;
        num[2]=note;
        return num;
    }

 

6.將輸出的內容寫入特定的文件中

6.1普通的輸出

clw這三個功能可以在這里進行相應的輸出

private static void output(String output_file, String com,int num) {
        // TODO Auto-generated method stub
        File txt=new File(output_file);
        try{
            FileWriter fw=new FileWriter(txt,true);//參數為true代表可以追加寫入
            BufferedWriter out = new BufferedWriter(fw);
            out.write(txt_name+","+com+":"+num+"\r\n");
            out.close();
        }
        catch(IOException e){
            System.out.println("指定輸出文件不存在");
        }
    }

 

6.2統計代碼后的輸出

僅用於輸出統計代碼的信息

private static void code_output(String output_file, String com,int []num) {
        // TODO Auto-generated method stub
        File txt=new File(output_file);
        try{
            FileWriter fw=new FileWriter(txt,true);//參數為true代表可以追加寫入
            BufferedWriter out = new BufferedWriter(fw);
            out.write(txt_name+","+com+":"+num[0]+"/"+num[1]+"/"+num[2]+"\r\n");
            out.close();
        }
        catch(IOException e){
            System.out.println("指定輸出文件不存在");
        }
    }

 

6.3輸入的是路徑的時候

此處的work是對第1條中judge后的所有flag進行判斷並執行相應功能。第7條對work額外說明。

此處通過*進行分割,前面的是路徑,后面的是文件后綴。

private static void files_output(String path_name){
        String []path=path_name.split("\\*");
        File file = new File(path[0]);//路徑boolean exist_flag=false;
        if(file.exists()){
            String []files=file.list();
            if(files.length==0){
                System.out.println("指定的文件夾是空的");
            }
            else {
                for(String f:files){
                    if(f.endsWith(path[1])){
                        exist_flag=true;
                        txt_name=f;
                        file_name=path[0]+f;
                        work();
                    }
                }
            }
            if(exist_flag==false){
                System.out.println("不存在符合要求的文件");
            }
        }
        else{
            System.out.println("指定路徑或文件不存在");
        }    
    }

7.主函數

此處的函數中也用到了work()。

實際上work是個void類型的函數,用到的都是全局變量,所以並沒有太復雜的結構,以后在改善程序性能的時候,在此函數的基礎上會做出完善,減少全局變量等,增加程序的安全性;

另外關於work的功能,只有一個,就是根據flag輸出打印最終結果。

所以不再貼出work的代碼。

private static void files_output(ArrayList<String> path_name){
        for(int i=0;i<path_name.size();i++){
            File file=new File(path_name.get(i));
            if(file.exists()){
                txt_name=file.getName();
                file_name=path_name.get(i);
                work();
            }
            else{
                System.out.println("指定路徑或文件不存在");
            }    
        }
    }

8.關於全局變量

不得不說確實太多了。另外關於下面代碼中自帶的路徑,其實是我自己測試用,打包成EXE后肯定是要去除的。

    static boolean c_flag=false;
    static boolean w_flag=false;
    static boolean l_flag=false;
    static boolean o_flag=false;
    static boolean a_flag=false;
    static boolean s_flag=false;
    static boolean e_flag=false;
    static boolean file_flag=false;
    static boolean all_flag=false;
    static boolean star_flag=false;
    static boolean path_flag=false;
    static boolean stop_flag=false;
    static String txt_name;
    static ArrayList<String>pathname=new ArrayList<String>();
    static String stoplist="D:\\myeclipse8.5\\workspace\\wordcount\\stoplist\\";
    static String file_name="D:\\myeclipse8.5\\workspace\\wordcount\\inputfiles\\";
    static String output_name="D:\\myeclipse8.5\\workspace\\wordcount\\outputfiles\\";

9.關於測試的設計

第一次像這樣比較正式的進行軟件的測試。

個人的思路是:程序分為多個函數,每個函數根據指令執行不同的功能可能會產生bug,不同指令之間的組合也有可能會產生bug等,所以測試用例的要點為:

1、必須實驗所有的功能

2、實驗幾組不同功能的組合,看是否能達到預期效果

3、使用不同的測試用例

下面是測試的截圖,主要對input的內容進行測試,內容會發生改變(實際上文件內容是以前的各種排序算法)。

9.1.c.o組合

-c input.txt -o output.txt

 

9.2.w.c.o組合

-w -c input.txt -o output.txt

 

 

 

9.3 l.w.e.o.組合

-l -w input.txt -e stoplist.txt -o output.txt

 

9.4 *.e.o組合

-* input.txt -e stoplist.txt -o output.txt

 

 

 

 

9.5 a.o組合

-a input.txt  -o output.txt

9.6 s,w,o.組合

此處input的副本是很早之前用的測試文件,所以三個副本的內容相同,但是和現在的input文件內容不想同

-s -w D:/myeclipse8.5/workspace/wordcount/inputfiles/*.txt -o output.txt

9.7 s,l,w,e,o組合

  -s -w -l  D:/myeclipse8.5/workspace/wordcount/inputfiles/*.txt -e stoplist.txt  -o output.txt

9.8 c,l組合

-l -c input.txt 

 

9.9  a,l,w,e,c組合

-l -c -w -a input.txt -e stoplist.txt

9.10 所有指令的組合

 -s -l -c -w -a D:\\myeclipse8.5\\workspace\\wordcount\\inputfiles\\*.txt -e stoplist.txt -o output.txt

 

10、參考文獻

 

正確的分析路徑(-s指令)的代碼:

private static void files_output(String path_name){
        String []path=path_name.split("\\*");
        File file=new File(path[0]);
        if(file.exists()){
            File[]files=file.listFiles();
            if(files!=null){
                for(File f:files){
                    if(f.getName().endsWith(path[1])){
                        txt_name=f.getName();
                        file_name=f.getAbsolutePath();
                        work();
                    }
                }
            }
            else{
                System.out.println("文件夾內容為空");
            }
        }
        else{
            System.out.println(path[0]+":指定路徑或文件不存在");
        }            
        
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM