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