热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:软件工程wcproject(JAVA)

篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件工程wc-project(JAVA)相关的知识,希望对你有一定的参考价值。Github

篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件工程 wc-project(JAVA)相关的知识,希望对你有一定的参考价值。


Github项目连接

一、项目简介

        该项目是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。

二、项目实现情况

    ?基本功能

       ? -c 返回文件的字符数 (实现)

       ? -w 返回文件的词的数目 (实现)

       ? -l 返回文件的行数 (实现)

   ?扩展功能   

              ?  -s 递归处理目录下符合条件的文件(实现)

        ? -a 返回更复杂的数据(代码行/空行/注释行)(实现)

        ? 支持各种文件的通配符(*,?)(实现)

   ?高级功能

       ? 基本的Windows GUI 程序操作(未实现)

        ? 支持通过图形界面选取文件(未实现)

        ? 支持通过图形界面展现文件的信息(未实现)

三、PSP
















































































































































































































































PSP2.1









Personal Software Process Stages









预估耗时(分钟)









实际耗时(分钟)









Planning









计划









 30









 42









· Estimate









· 估计这个任务需要多少时间









 30









 42









Development









开发









 720









 960









· Analysis









· 需求分析 (包括学习新技术)









 90









 102









· Design Spec









· 生成设计文档









 20









25









· Design Review









· 设计复审 (和同事审核设计文档)









 10









 12









· Coding Standard









· 代码规范 (为目前的开发制定合适的规范)









 10









13









· Design









· 具体设计









 60









 65









· Coding









· 具体编码









 410









 422









· Code Review









· 代码复审









 60









 75









· Test









· 测试(自我测试,修改代码,提交修改)









 60









 246









Reporting









报告









120









 136









· Test Report









· 测试报告









90









95









· Size Measurement









· 计算工作量









10









 5









· Postmortem & Process Improvement Plan









· 事后总结, 并提出过程改进计划









 20









 36









合计









 









 870









 1138

四、解题思路

 1、本项目分为基本功能、扩展功能、高级功能。除了主类,将功能类基本分为一个基本功能类、三个扩展功能类(包括计算代码行、空行、注释行的类和递归查找的类和通配符处理的类,分别对应三个扩展功能要求)

 2、计算各种行或词的方法大致思路为:首先读入文件 -> 使用readLine()方法逐行读取 -> 依据计算的对象不同编写不同的计算方法

 3、递归处理:编写find()方法不断递归,查找文件如果是文件夹返回所有文件和文件夹的绝对路径接着再递归查找。如是文件则加入列表里,最后再将一个个列表里的对象取出处理。

 4、通配符处理:将用户输入的所有*或?分别用.*和.?代替(正则表达式的任意字符),并使用pattern类对象存储模式,递归查找符合条件的文件。

五、设计实现过程

功能简易基本流程图如下所示:

 技术分享图片

代码结构图如下所示,包括五个类(一个基本功能类,三个扩展功能类,一个properties类),一个类对应几个方法。

技术分享图片

六、关键代码与注释思路说明

-c 返回文件的字符数


public void strNum(String p) { //计算字符数的方法
try {
BufferedReader bw
= new BufferedReader(new FileReader(p)); //读入文件
while((c2=bw.readLine())!=null) {
String k
= c2.replace(" ",""); //将空格全部替换成空
a2=a2+k.length(); //每读一行,累计字符数
sx.setStrNum(a2);
}
System.out.println(
"该文件的字符数为:"+sx.getStrNum());
bw.close();
}
catch (FileNotFoundException e) {
System.out.println(
"无法找到指定文件");
}
catch (IOException e) {
System.out.println(
"I/O错误");
}
}

 -w 返回文件的词的数目


public void wordNum(String p) { //计算单词数的方法
try {
BufferedReader bw
= new BufferedReader(new FileReader(p)); //读入文件
StringBuffer sb=new StringBuffer();
while((c3=bw.readLine())!=null) { //readline读取到换行不算为null
if(c3.matches("")==false) { //字符比较不能直接!=,如果读取的行非空执行下面语句
sb.append(c3+"\\s"); //将读取到的内容追加在StringBuffer对象中,在结尾加上一个空白字符避免与下行的首部相连
}
}
c3
=sb.toString(); //转为字符串模式
String[] strings=c3.split("[^\\w]"); //以非词字符为分隔 将词分开
System.out.println("该文件单词个数为:"+(strings.length-1));
bw.close();
}
catch (FileNotFoundException e) {
System.out.println(
"无法找到指定文件");
}
catch (IOException e) {
System.out.println(
"I/O错误");
}
}

 -l 返回文件的行数


public void lineNum(String p) { //计算行数的方法
try {
BufferedReader bw
= new BufferedReader(new FileReader(p));//读入文件
while(bw.readLine()!= null) { //当读行不为空
a1++; //行数加一
sx.setLineNum(a1);
}
System.out.println(
"该文件的行数为:"+sx.getLineNum());
bw.close();
//关闭流
} catch (FileNotFoundException e) { //捕获错误1
System.out.println("无法找到指定文件");
}
catch (IOException e) { //捕获错误2
System.out.println("I/O错误");
}
}

  -s 递归处理目录下符合条件的文件


public class extended_function_recursion { //扩展功能第二部分支持 -s递归处理目录下符合条件的文件

basic_function bf
= new basic_function(); //创建基本功能类对象
extended_function ef = new extended_function(); //创建扩展功能类第一部分对象

public void recursion(String fileName, String filePath) { //递归处理目录下符合条件的文件
List l = new ArrayList();
find(
new File(filePath),fileName,l);
String path
= null;
if(l.size()>=1)path = l.get(0); //提取文件路径
System.out.println("该目录下符合要求的文件的绝对路径为:"+path);
}
public static void find(File file,String fileName,List l) {
if (file.isDirectory()) { //如果是一个文件夹,返回true
File[] f1 = file.listFiles(); //返回某个当前目录下的所有文件和文件夹的绝对路径,返回的是File数组
for (File f : f1) {
find(f,fileName,l);
//递归执行
}
}
else{
if(file.getName().equals(fileName)){
l.add(file.getAbsolutePath());
//获取绝对路径
}
}
}
}

-a 返回更复杂的数据(代码行 / 空行 / 注释行)

计算代码行部分:


public void codeline(String p) { //计算代码行方法,判断代码行标准:本行包括多于一个字符的代码
try {
BufferedReader bw
= new BufferedReader(new FileReader(p));//读入文件
while( (e1=bw.readLine())!= null) {
if(e1.length()>=2){ //若本行内容长度多于一个字符
j1++;
}
sx.setCodeLine(j1);
}
System.out.println(
"该文件的代码行数为:"+sx.getCodeLine());
bw.close();
}
catch (FileNotFoundException e) {
System.out.println(
"无法找到指定文件");
}
catch (IOException e) {
System.out.println(
"I/O错误");
}
}

-a 返回更复杂的数据(代码行 / 空行 / 注释行)

计算空行部分:


public void blankline(String p) { //计算空行的方法,判断空行标准:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符
try {
BufferedReader bw
= new BufferedReader(new FileReader(p));
while( (e2=bw.readLine())!= null) {
o
= e2.matches("\\s+||\\S"); //e2不加双引号!!,如果读行内容匹配多个空白字符或只有一个非空白字符,空行加一
if(o == true) { //=是错的!!
j2++;
}
sx.setBlankLine(j2);
}
System.out.println(
"该文件的空行数为:"+sx.getBlankLine());
bw.close();
}
catch (FileNotFoundException e) {
System.out.println(
"无法找到指定文件");
}
catch (IOException e) {
System.out.println(
"I/O错误");
}
}

-a 返回更复杂的数据(代码行 / 空行 / 注释行)

计算注释行部分:


public void commentline(String p) { //计算注释行的方法,判断注释行标准:本行不是代码行(包括多于一个字符的代码),并且本行包括注释,注释前可有}
try {
BufferedReader bw
= new BufferedReader(new FileReader(p));
while( (e3=bw.readLine())!= null) {
if(e3.contains("//")) { //如果本行有//
o = (e3.substring(0, e3.indexOf("//"))).matches("\\S{0,1}");//判断//前如果为一个或零个字符则为注释行
if(o == true) {
j3
++;}
}
else if(e3.contains("/*")){ //同理
o = (e3.substring(0, e3.indexOf("/*"))).matches("\\S{0,1}");
if(o == true) {
j3
++;}
}
else if(e3.contains("*/")){ //同理
o = (e3.substring(0, e3.indexOf("*/"))).matches("\\S{0,1}");
if(o == true) {
j3
++;}
}
sx.setCommentLine(j3);
}
System.out.println(
"该文件的注释行数为:"+sx.getCommentLine());
bw.close();
}
catch (FileNotFoundException e) {
System.out.println(
"无法找到指定文件");
}
catch (IOException e) {
System.out.println(
"I/O错误");
}
}

支持各种文件的通配符(*,?)部分:


public class tong_pei { //扩展功能第三部分,支持各种文件的通配符(*,?)
public File[] getFiles(String dir,String s) { //getFiles方法,返回File数组存取路径
File file = new File(dir);
s
= s.replace("*", ".*");//将*换为正则表达式的零次或多次的任意字符
s = s.replace("?", ".?");//将?换为正则表达式的一次或没有的任意字符
Pattern p = Pattern.compile(s); //用compile()方法设置匹配模式
ArrayList list = filePattern(file, p);//调用filePattern方法
File[] rtn = new File[list.size()];
list.toArray(rtn);
return rtn;
}

public ArrayList filePattern(File file, Pattern p) {
if (file == null) { //如果文件为空返回空
return null;
}
else if (file.isFile()) { //判断该文件是否标准文件
Matcher fMatcher = p.matcher(file.getName());
if (fMatcher.matches()) {
ArrayList list
= new ArrayList();
list.add(file);
return list;
}
}
else if (file.isDirectory()) { //判断文件是否为文件夹
File[] files = file.listFiles();
if (files != null && files.length > 0) {
ArrayList list
= new ArrayList();
for (int i = 0; i ) {
ArrayList rlist = filePattern(files[i], p);
if (rlist != null) {
list.addAll(rlist);
}
}
return list;
}
}
return null;
}
}

properties类


public class properties { //Properties类
int strNum=0;
int wordNum=0;
int lineNum=0;
int codeLine=0; //代码行
int blankLine=0; //空行
int commentLine=0; //注释行

public int getCodeLine() {
return codeLine;
}
public void setCodeLine(int codeLine) {
this.codeLine = codeLine;
}
public int getBlankLine() {
return blankLine;
}
public void setBlankLine(int blankLine) {
this.blankLine = blankLine;
}
public int getCommentLine() {
return commentLine;
}
public void setCommentLine(int commentLine) {
this.commentLine = commentLine;
}
public int getStrNum() {
return strNum;
}
public void setStrNum(int strNum) {
this.strNum = strNum;
}
public int getWordNum() {
return wordNum;
}
public void setWordNum(int wordNum) {
this.wordNum = wordNum;
}
public int getLineNum() {
return lineNum;
}
public void setLineNum(int lineNum) {
this.lineNum = lineNum;
}
}

主类


import java.io.File;
import java.util.Scanner;
public class wc {
public static void main(String[] args) {
basic_function mts
= new basic_function(); //以下四行创建功能类对象
extended_function wtf = new extended_function();
extended_function_recursion efr
= new extended_function_recursion();
tong_pei tp
= new tong_pei();


Scanner scan
= new Scanner(System.in);//创建Scanner类对象
if (scan.hasNext()) { //若有输入
String str1 = scan.nextLine();
if((str1.substring(0,2)).equals("-l"))mts.lineNum(str1.substring(3,str1.length()));
if((str1.substring(0,2)).equals("-c"))mts.strNum(str1.substring(3,str1.length()));
if((str1.substring(0,2)).equals("-w"))mts.wordNum(str1.substring(3,str1.length()));
if((str1.substring(0,2)).equals("-a")) {
wtf.codeline(str1.substring(
3,str1.length())); //substring() 方法返回的子串包括 start 处的字符,但不包括 stop 处的字符
wtf.blankline(str1.substring(3,str1.length()));
wtf.commentline(str1.substring(
3,str1.length()));
}
if((str1.substring(0,2)).equals("-s")) {
String arrays[]
= str1.split(" ");
File f[]
= tp.getFiles(arrays[2],arrays[1]); //调用tong_pei类中getFiles()方法
for(File ff:f) {
efr.recursion(ff.getName(),ff.getAbsolutePath());
}
}
if((str1.substring(0,4)).equals("-s-a")) {
basic_function bf
= new basic_function(); //创建基本功能类对象
extended_function ef = new extended_function(); //创建扩展功能类第一部分对象
String arrays[] = str1.split(" ");
File f[]
= tp.getFiles(arrays[2],arrays[1]); //调用tong_pei类中getFiles()方法
for(File ff:f) {
efr.recursion(ff.getName(),ff.getAbsolutePath());
System.out.println(
"以下为递归处理目录下符合条件的文件的属性:");
bf.lineNum(ff.getAbsolutePath());
//以下为文件属性
bf.strNum(ff.getAbsolutePath());
bf.wordNum(ff.getAbsolutePath());
ef.codeline(ff.getAbsolutePath());
ef.blankline(ff.getAbsolutePath());
ef.commentline(ff.getAbsolutePath());
}
}
scan.close();
//关闭流
}
}
}

七、测试运行结果

-c 返回文件的字符数:

 技术分享图片

 -w 返回文件的词的数目:

技术分享图片

-l 返回文件的行数:

技术分享图片

-a 返回更复杂的数据(代码行 / 空行 / 注释行):

技术分享图片

 -s 递归处理目录下符合条件(条件:用户指定的文件)的文件:

技术分享图片

 -s 递归处理目录下符合条件的文件(使用通配符):

技术分享图片

-s-a 递归处理目录下符合条件的文件(使用通配符),并显示文件的属性:

技术分享图片

八、代码覆盖率

技术分享图片

 

九、项目小结

        通过此次项目的锻炼,我对java程序编写的熟练度又有所提升,收获比我在做项目之前意想的要丰富得多,但同时也认识到了自身的许多不足。以前编写程序比较随意,按自己喜欢的方式去写,也不喜欢写注释,导致以后的管理十分困难。但此次的软件工程项目,我通过自己学习到的一些软件工程的知识,不仅仅是编写代码,在编写之前还进行了项目的计划与各种设计,同时也在编写完成后进行了许多的测试调节并记录问题。在完成项目之后拿来与以前的项目项目相比从管理或者功能的完善程度都有明显的提升。代码细节部分,也学到了一些平常少用到的知识点,如正则表达式。同时也发现了一些平时易犯的低级错误,如substring() 方法返回的子串包括 start 处的字符,但不包括 stop 处的字符等。从PSP表来看,自己预估的时间还并不太准确,特别是测试修改部分的时间比想象中要多得多,在以后的学习中还需多积累经验。



推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
author-avatar
起来吧52
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有