Wordcount基础功能和拓展实现(java)
1.项目简介:
可执行程序命名为:wc.exe,该程序处理用户需求的模式为:
wc.exe [parameter] [input_file_name]
存储统计结果的文件默认为result.txt,放在与wc.exe相同的目录下
码云链接如下:
https://gitee.com/this-hui/Homework
2.项目PSP表格:
PSP表格如下:
PSP2.1 |
PSP阶段 |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
40 |
60 |
· Estimate |
· 估计这个任务需要多少时间 |
250 |
350 |
Development |
开发 |
250 |
300 |
· Analysis |
· 需求分析 (包括学习新技术) |
50 |
60 |
· Design Spec |
· 生成设计文档 |
60 |
60 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
30 |
20 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
20 |
30 |
· Design |
· 具体设计 |
30 |
30 |
· Coding |
· 具体编码 |
150 |
200 |
· Code Review |
· 代码复审 |
30 |
30 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
30 |
30 |
Reporting |
报告 |
60 |
0 |
· Test Report |
· 测试报告 |
30 |
0 |
· Size Measurement |
· 计算工作量 |
5 |
5 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
10 |
20 |
|
合计 |
1045 |
11 |
2.1基础功能:
wc.exe -l 统计文件的行数
wc.exe -w 统计文件的单词数
wc.exe -c 统计文件的字符数
wc.exe -d 统计文件的注释行
wc.exe -n 统计文件的空行
3.代码设计:
一共设计了四个类和一个测试类:
首先是WordCount主类:
1 import java.io.IOException; 2 3 public class WordCuont { 4 //主程序用于判断 5 public static void main(String [] args) { 6 Creat_data data =new Creat_data();//创建的数据类 7 ToolUtil toolUtil = new ToolUtil();//创建的工具类 8 for(int i=0 ;i<args.length;i++) 9 { 10 11 if(args[i].startsWith("-")) { 12 13 switch (args[i]) 14 { 15 case "-c"://检查字符数 16 data.F_Characters=true; 17 break; 18 case "-l"://检查行数 19 data.F_Lines=true; 20 break; 21 case "-w"://检查单词数 22 data.F_wods=true; 23 break; 24 case "-d"://检查注释行 25 data.F_difine=true; 26 break; 27 case "-n"://检查空行 28 data.F_NULL=true; 29 break; 30 case "-o": 31 if(!args[i+1].startsWith("-")) 32 { 33 data.Output_file=args[i+1]; 34 i++; 35 }else { 36 System.out.println("Your intput is illigal!"); 37 System.exit(0); 38 } 39 break; 40 default: 41 System.out.println("Your intput is illigal!"); 42 break; 43 44 } 45 } 46 else data.all_file.add(args[i]); 47 48 49 } 50 //判断然后传入数据 51 if(data.F_Characters) 52 { 53 data.Result+=toolUtil.ReturnChara(data.all_file)+"\r\n"; 54 } 55 if(data.F_Lines) 56 { 57 data.Result+=toolUtil.ReturnLines(data.all_file)+"\r\n"; 58 59 } 60 if(data.F_wods) 61 { 62 data.Result+=toolUtil.ReturnWords(data.all_file)+"\r\n"; 63 } 64 if(data.F_difine) 65 { 66 try { 67 data.Result+=toolUtil.difflineGUI(data.all_file)+"\r\n"; 68 } catch (IOException e) { 69 // TODO Auto-generated catch block 70 e.printStackTrace(); 71 } 72 } 73 if(data.F_NULL) 74 { 75 try { 76 data.Result+=toolUtil.NULL(data.all_file)+"\r\n"; 77 } catch (IOException e) { 78 // TODO Auto-generated catch block 79 e.printStackTrace(); 80 } 81 } 82 83 System.out.println(data.Result); 84 toolUtil.OutpuFile(data.Output_file,data.Result); 85 } 86 87 }
然后是用来实际操作的工具类,工具类中主要是对文件进行操作,其中对注释行和空行的判断尤为重要,因为在判定空行时enter键和空格键会产生干扰,在判定注释行时要考虑全面注释的语句开头:
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Set; import java.util.regex.Pattern; public class ToolUtil { //创建检查字符数,行数,单词数,空行,注释行的方法 public String ReturnChara(Set<String> all_file) { // TODO Auto-generated method stub] Creat_data data_R=new Creat_data(); //调用数据类创建数据和IO流 byte [] S_byte=new byte[20*1024]; int len =S_byte.length; int Byetes=0; try { for(String all_file1:all_file) { data_R.in =new FileInputStream(all_file1); while((Byetes = data_R.in .read(S_byte,0,len))!=-1) { data_R.Count+=Byetes; } data_R.result+=all_file1+",字符数:"+data_R.Count+" "; data_R.Count =0; } }catch(FileNotFoundException e) { System.out.println("文件输入错误请检查后重新输入"); System.exit(0); }catch(IOException e) { e.printStackTrace(); }finally { try { data_R.in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return data_R.result; } public String ReturnLines(Set<String> all_file) { // TODO Auto-generated method stub Creat_data data_L=new Creat_data(); try { for(String all_file1:all_file) { data_L.in=new FileInputStream(all_file1); data_L.isr=new InputStreamReader(data_L.in); data_L.bis=new BufferedReader(data_L.isr); while(data_L.bis.readLine()!=null) { data_L.Count++; } data_L.result+=all_file1+",行数:"+data_L.Count+" "; data_L.Count=0; } }catch(FileNotFoundException e) { System.out.println("文件输入错误请检查后重新输入"); System.exit(0); }catch(IOException e) { e.printStackTrace(); }finally { data_L.Close(); } return data_L.result; } public String ReturnWords(Set<String> all_file) { // TODO Auto-generated method stub Creat_data data_W=new Creat_data(); StringBuffer saveString = new StringBuffer(); String tmp = ""; //缓存字符串 try { for(String all_file1:all_file) { data_W.in=new FileInputStream(all_file1); data_W.isr=new InputStreamReader(data_W.in); data_W.bis=new BufferedReader(data_W.isr); while((tmp=data_W.bis.readLine())!=null) { saveString.append(tmp); } tmp =saveString.toString(); String [] all= tmp.split("[\\s+,\\.\n]"); data_W.Count = all.length; data_W.result+=all_file1+",单词数:"+data_W.Count+" "; } }catch(FileNotFoundException e) { System.out.println("文件输入错误请检查后重新输入"); System.exit(0); }catch(IOException e) { e.printStackTrace(); }finally { data_W.Close(); } return data_W.result; } public boolean OutpuFile(String output_file, String Result) { // TODO Auto-generated method stub File OUtputFile =new File(output_file); FileOutputStream os =null; byte[] b=null; try { if(!OUtputFile.exists()) { OUtputFile.createNewFile(); } os = new FileOutputStream(OUtputFile); b= Result.getBytes(); os.write(b); }catch(IOException e) { e.printStackTrace(); }finally { try { os.close(); }catch(IOException e) { e.printStackTrace(); } } return true; } String difflineGUI(Set<String> all_file) throws IOException { int Space_line = 0; Creat_data data_d =new Creat_data(); BufferedReader bufr = null; for (String all_files : all_file) { bufr = new BufferedReader(new InputStreamReader(new FileInputStream(all_files))); Pattern spaceLinePattern = Pattern.compile("^\\s*$"); String line = null; while((line = bufr.readLine()) != null) { if (spaceLinePattern.matcher(line).find()) { Space_line ++; } } data_d.result+=all_files+",空行数:"+Space_line+" "; } return data_d.result; } String NULL(Set<String> all_file) throws IOException { int Sode_line = 0; Creat_data data_n =new Creat_data(); BufferedReader bufr = null; for (String all_files : all_file) { bufr = new BufferedReader(new InputStreamReader(new FileInputStream(all_files))); Pattern nodeLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+", Pattern.MULTILINE + Pattern.DOTALL); String line = null; while((line = bufr.readLine()) != null) { if (nodeLinePattern.matcher(line).find()) { Sode_line ++; } } data_n.result+=all_files+",注释行:"+Sode_line+" "; } return data_n.result; } }
创建数据的数据类,类似于set和get数据的个人类,我们将在工具类中会用到的数据封装到类中,并把IO流操作封装到数据类中,使工具类更加的简洁:
1 import java.io.BufferedReader; 2 import java.io.FileInputStream; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.util.HashSet; 7 import java.util.Set; 8 9 public class Creat_data { 10 11 12 Set<String> all_file =new HashSet<String>();//创建文件列表 13 String Output_file = "result.txt"; 14 String Result ="";//创建结果的字符集 15 //用于判定操作的bool变量 16 boolean F_Characters=false; 17 boolean F_Lines =false; 18 boolean F_wods =false; 19 public boolean F_difine=false; 20 public boolean F_NULL=false; 21 int Count = 0; 22 String result = ""; 23 //创建可以操作的IO流 24 FileInputStream in = null; 25 InputStreamReader isr = null; 26 BufferedReader bis = null; 27 FileOutputStream os = null; 28 29 30 //关闭IO流 31 public void Close() { 32 33 try { 34 in.close(); 35 isr.close(); 36 bis.close(); 37 } catch (IOException e) { 38 // TODO Auto-generated catch block 39 e.printStackTrace(); 40 } 41 42 } 43 }
4.测试计划过程:
最后我们使用java自带的工具Junit来进行测试,这个在以前我们学过的设计模式和Android应用开发时都用到过,注意在插入文件的时候一定要使用绝对路径,否则会因为路径不支持而导致文
件读取不到从而导致程序崩溃。
import java.io.IOException; import java.util.HashSet; import java.util.Set; public class test { @org.junit.Test public void testDifine() { Set<String> all_files = new HashSet<String>(); String file1 = "C:\\Users\\Rise\\eclipse-workspace\\Work\\src\\test.java"; all_files.add(file1); try { System.out.println(new ToolUtil().difflineGUI(all_files)); System.out.println(new ToolUtil().NULL(all_files)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace();//hfawihfia } } @org.junit.Test public void testReturnCharacters() { Set<String> all_files = new HashSet<String>(); String file1 = "C:\\Users\\Rise\\eclipse-workspace\\Work\\src\\test.java"; all_files.add(file1); System.out.println(new ToolUtil().ReturnChara(all_files)); } @org.junit.Test public void testReturnWords() { Set<String> all_files = new HashSet<String>(); String file1 = "C:\\Users\\Rise\\eclipse-workspace\\Work\\src\\test.java"; all_files.add(file1); System.out.println(new ToolUtil().ReturnWords(all_files)); } @org.junit.Test public void testReturnLines() { Set<String> all_files = new HashSet<String>(); String file1 = "C:\\Users\\Rise\\eclipse-workspace\\Work\\src\\test.java";//哈哈哈哈 all_files.add(file1); System.out.println(new ToolUtil().ReturnLines(all_files)); } @org.junit.Test public void testOutputFile() { String all_files = "result.txt"; String context = "OutPutFile test !"; new ToolUtil().OutpuFile(all_files, context); } }
测试结果如下:
基本的代码就已经完成了,然后我们去生成exe.文件并进行测试:
5.总结:
在这次的实验中大部分的时间其实还是学习java的IO流操作,在认真学习了java的IO流操作之后这个实验用java语言来写便特别的简单,而在实现的过程中我应该改了3次代码,第一次代码基础功能实现以后我发现我写出来的东西跟C语言差不多首先没有表现面向对象的思想其次代码的格式也不是特别的规范,所以我决定修改,把创建数据,创建和关闭IO流的操作抽象出了一个类,我只需要每次实例化这个类便可以创建对应的IO流并不用再重复的书写,第二次将主函数精简,开始的时候我的工具类方法有些是写到主函数的类中的,起初以为简单的方法在主函数里写也没有什么,但是在最后检查的时候我发现这样及其不规范,别人来看代码时会常常忘记看下面的方法,而只看主函数的逻辑就走,所以我又一次重写到了工具类里面,第三次是使用Junit来进行测试,其实同学可能会有和我一样的做法,就是不断地打印来进行测试,不断的在程序中间插入打印语句测试代码是否正确,这样十分恼火,不仅增添的时候头疼,删除的时候更头疼,所以我选择了编程工具提供给我们的便利,junit十分的方便,也非常的直观,以后我会更加注重他的使用。