---恢复内容开始---
个人项目:WC
一,GitHub地址:https://github.com/Cercis-chinensis/wc
二 , PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | 耗时占比 |
| Planning | 计划 | 30 | 20 | 1 |
| Estimate | · 估计这个任务需要多少时间 | 30 | 20 | 1 |
| Development | 开发 | 890 | 1710 | 92 |
| Analysis | · 需求分析 | 30 | 20 | 1 |
| Design Spec | · 生成设计文档 | 30 | 20 | 1 |
| Design Review | · 设计复审 | 40 | 20 | 1 |
| Coding Standard | · 代码规范 | 50 | 10 | 0.5 |
| Design | · 具体设计 | 60 | 170 | 10 |
| Coding | · 具体编码 | 600 | 1500 | 80 |
| Code Review | · 代码复审 | 20 | 60 | 3 |
| Test | · 测试(自我测试,修改代码,提交修改) | 60 | 80 | 4 |
| Reporting | 报告 | 110 | 130 | 7 |
| Test Report | · 测试报告 | 60 | 80 | 4 |
| Size Measurement | · 计算工作量 | 40 | 30 | 1.5 |
| Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 20 | 1 |
| Total | 合计 | 1860 |
三,解题思路
在看到题目要求后,我对应着个人开发流程(PSP)来作为思考的方向。所以,对题目分析需求,初步分析时,我将需求之间的关系大致分为三部分。然后进行相应的计划设计。初步设计时,将这个项目的代码关于类的设计主要分为四部分。分别时基本功能类(统计字符,行数,单词数、查看空行、注释行、代码行),扩展功能类expand(递归查看文件),高级功能类(显示GUI),还有主类(主要来接受控制台传输的字符串,提取并处理传输给各种调用类)。
在考虑好各类的所要实现的功能后,进一步大致考虑类之间的相互关系与调用。通过考虑上面这些,对此写下设计计划。
之后对四个类进行大致设计,根据各类所要实现功能以及各类之间的关系来设计各种类的形式,同时,思考该如何实现分配给各个类的功能,同时联想到相应的语言知识,思考着如何构建知识储备与所要实现功能之间的关联,将如何实现功能的操作逐步细分,当细分后的操作与已知知识点有所联系时,稍作记录,遇到不懂的部分时,在网上查找各种资料。
在对各类所实现功能的编写有着大概掌握后,对每个类的内部进行更详尽的编写。在编写时,我设置一个另外用于测试的test主类,目的是用来测试我所要写的逻辑,相关代码块,以及所引用各种包等等操作是否符合实际应用。
完成一个功能,就进行测试,为避免后面引起混乱。同时,在编写过程中,根据实际来对类的结构,方法的结构经行一些修改,来更好地完成项目。
在做此次项目的过程中,思路大致如上。
四,实现设计过程
根据需求之间的联系,将此次项目分为四个类,分别是基本功能类(实现行,字符,单词的统计),扩展功能类(实现递归处理文件)高级功能类(GUI),以及主类。
基本功能类Base();
扩展功能类Expand();
高级功能类CFrame();
主类wc();
类之间的关系图:

各类的内部大致描述:
主类wc:
接受控制台所输入的字符串(“-c” “-w”等等以及文件路径),对字符串进行处理,首先是将标识符与路径分开存储,根据标识符使用switch——case来创建相应的对象,调用相应的方法。
以下为主类的主要代码部分:
String[] st = {""};
Expand ep;
while(!st[0].equals("end")){
System.out.print("\nwc.exe:");
st=inp.nextLine().split("\\s+");
switch(st[0]){
case "-c":
if(Files.notExists(Paths.get(st[1]),LinkOption.NOFOLLOW_LINKS))
System.out.println("输入出错");
else System.out.println("字符数为:"+Base.count(st[1], 'c'));
continue;
case "-w":
if(Files.notExists(Paths.get(st[1]),LinkOption.NOFOLLOW_LINKS))
System.out.println("输入出错");
else System.out.println("词数为:"+Base.count(st[1], 'w'));
continue;
case "-l":
if(Files.notExists(Paths.get(st[1]),LinkOption.NOFOLLOW_LINKS))
System.out.println("输入出错");
else System.out.println("行数为:"+Base.count(st[1], 'l'));
continue;
case "-s":
if(Files.notExists(Paths.get(st[1]),LinkOption.NOFOLLOW_LINKS))
System.out.println("输入出错");
else ep = new Expand(st[1]);
continue;
case "-x":
CFrame fr=new CFrame();
continue;
case "-n":
if(Files.notExists(Paths.get(st[1]),LinkOption.NOFOLLOW_LINKS))
System.out.println("输入出错");
else System.out.println("空行数为:"+Base.count(st[1], 'n'));
continue;
case "-e":
if(Files.notExists(Paths.get(st[1]),LinkOption.NOFOLLOW_LINKS))
System.out.println("输入出错");
else System.out.println("单行注释行数为:"+Base.count(st[1], 'e'));
continue;
case "-o":
if(Files.notExists(Paths.get(st[1]),LinkOption.NOFOLLOW_LINKS))
System.out.println("输入出错");
else System.out.println("代码行行数为:"+Base.count(st[1], 'o'));
continue;
default:
System.out.println("出错!请按所设定的形式输入!");
continue;
}
}
inp.close();
System.out.println("程序结束");
}
基本功能类Base:
统计字符数,单词数,行数,空行数,注释行数,代码行数,同时通过主类传给base类的标识符,返回不同的值。
public static int count(String path,char c) throws IOException{
BufferedReader brfile;
//注意int的上限》?
int cnum=0;
int wnum=0;
int lnum=0;
int nline=0;
int eline=0;
int oline=0;
brfile= new BufferedReader(new InputStreamReader(new FileInputStream(path)));
//改先分。分析效能时
String str1=null;
while((str1=brfile.readLine())!=null) {
cnum +=str1.length();
wnum +=str1.split("\\W+").length;
if(str1.matches("\\s*")) nline++;
if(str1.matches("\\s*//.*")) eline++; //单行注释, 多行注释待解决
lnum++;
}
oline=lnum-nline-eline;
brfile.close();
if(c=='w')return wnum;
else if(c=='c')return cnum;
else if (c=='l')return lnum;
else if(c=='n') return nline;
else if(c=='e')return eline;
else if(c=='o')return oline;
else return 0;
Expand类
递归进入文件夹,如果目录下还有文件夹,则进入其中,并识别运行符合条件的文件,在这里,我将符合条件的文件设为,以.txt .java .c .py .doc结尾的文件,当然,还可以进行相应的扩充。
递归进入文件夹读取文件:
private static void findf(String str) throws IOException {
File fl=new File(str);
File[] flist=fl.listFiles();
for(File f :flist) {
if(f.isDirectory()) {
findf(f.getAbsolutePath());
}else if(isfind(f.getName())) {
System.out.println(f.getName());
System.out.println("字符数为:"+Base.count(f.getAbsolutePath(), 'c'));
System.out.println("单词数为:"+Base.count(f.getAbsolutePath(),'w'));
System.out.println("行数为:"+Base.count(f.getAbsolutePath(), 'l')+
" 其中,空行数为:"+Base.count(f.getAbsolutePath(), 'n')+
" 单行注释行数为:"+Base.count(f.getAbsolutePath(), 'e')+
" 代码行为:"+Base.count(f.getAbsolutePath(), 'o'));
}
}
上面代码中,的isfind()方法来用于识别符合条件文件:
static boolean isfind(String name) {
if(name.endsWith(".java"))return true;
else if(name.endsWith(".txt"))return true;
else if(name.endsWith(".c"))return true;
else if(name.endsWith(".py"))return true;
else if(name.endsWith(".doc"))return true;
else return false;
}
CFrame类:
主要是调用 文件选择器 来通过图形界面选择文件,同时通过提示框JOptionPane来返回处理后信息
JFileChooser fc=new JFileChooser();
fc.showOpenDialog(null);
file=fc.getSelectedFile();
JOptionPane.showMessageDialog(null,
"字符数为:"+Base.count(path,'c')+"\n字数为"+Base.count(path, 'w')+"\n行数为:"+Base.count(path, 'l')+"\n空行数:"+Base.count(path, 'n')+"\n单行注释行数:"+Base.count(path, 'e')+"\n代码行:"+Base.count(path, 'o'),"处理结果",
JOptionPane.INFORMATION_MESSAGE);
五,测试
控制台界面:

测试-c:
分别测试的是空文件,一个字符文件,一行字符的文件,以及一个源程序文件

测试-l:

测试-s:递归
文件夹视图:

直接对-s测试可以对Base中其他标识符有关代码进行测试,篇幅有限,尽可能提高测试代码率;

上面doc文件有关统计有错,说明doc格式与这种计算不符,同时,这可以说明可以匹配到.doc结尾的,以及可以递归进入文件夹。
测试-x:GUI

选择t4.java后的处理结果界面:
测试end:结束程序;

返回结果符合所预设结果。
六,总结
经历这次项目后,无疑的是,自己在有关编程方面的能力有着很大的提升。同时对旧知识的回忆,以及对新知识的学习与应用有着很大的帮助。这次作业经历,增加了个人对软件开发过程的认识,特别是PSP的过程,编码前的准备比编码的过程更为重要。在编码前的准备越是充分,编码的过程越是容易。
同时,也切实看到自身的不足,各方面的欠缺。导致这次试验效率非常低,前期设计的准备不足,导致后面编码时要经常对前面进行改动。各种能力,素养还需要更多地磨练。
任重而道远