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