一、github地址
https://github.com/Mazin-hub/MyWC.exe.git
二、PSP表格
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
|
·Estimate |
·估计这个任务需要多少时间 |
30 |
|
Development |
开发 |
1200 |
|
·Analysis |
·需求分析 (包括学习新技术) |
120 |
|
·Design Spec |
·生成设计文档 |
20 |
|
·Design Review |
·设计复审(和同事审核设计文档) |
0 |
|
·Coding Standard |
·代码规范(为目前的开发指定合适的规范) |
30 |
|
·Design |
·具体设计 |
20 |
|
·Coding |
·具体编码 |
150 |
|
·Code Review |
·代码复审 |
30 |
|
·Test |
·测试(自我测试,修改代码,提交修改) |
120 |
|
Reporting |
报告 |
60 |
|
·Test Report |
·测试报告 |
30 |
|
·Size Measurement |
·计算工作量 |
10 |
|
·Postmortem & Process Improvement Plan |
事后总结,并提出过程改进计划 |
15 |
|
Total |
合计 |
1865 |
三、解题思路
语言选择
刚看到wc.exe的基本功能时,就决定了用Java实现,实际上C的文件操作没怎么学,也只有Java有了解.感觉Java比C了解的多就选择了用Java
用到的知识
Java的File,I/O操作,这些我之前都有自主学习过,还算了解。还有一个要求是调用windows的GUI,不会用,在网上查找了一些资料,用了JFileChoose类,只用了Java自己的GUI控制,功能也能实现,就是不会调出windows的GUI。还有在个人项目作业里的附录,IDEA上用到的一些插件学习(包括代码规范,单元测试等)
四、设计实现过程
这个个人项目我并没有写出很多类,实际上是我对Java的类(class)了解还不够,我简单写了几个核心方法运行而已。
1. Print() 主要是输出一些不痛不痒的信息,自己加上的
2. JudgeDir() 判断输入的路径是文件还是目录,涉及到后面 选择哪个方法进行
3. SwitchMethod() 核心算法,对输入的parameter进行解析,选择方法进行输出,调用了下面5个方法的方法体,冗长是大问题,我觉得可以单独弄一个类。
4. countChar() 计算字符数
5. countRow() 计算行数
6. countWord() 计算单词数
7. countElse() 计算代码行、注释行、空行
8. Path() 路径转化方法,主要用于-s、-x选择的目录下的文件的路径筛选出来
程序结果:
1. 能用-w -c -l -a,-a有点针对源文件,其他文件也能执行。
2. -s能对目录、文件做出不同输出。包括文件计数。(有个缺陷,文件的数目太大需要手动调整保存路径的String[] 的大小)
3. -x能多次选择文件或目录,直至用户点击 Java GUI 的 “取消” 按钮结束。
五、代码说明
1. 计算字符数,本意是只计算可显示的字符数
public static void countChar(String s) throws Exception { FileReader in = new FileReader(s); int characterNum = 0; while (true) { int c = in.read(); if (c == -1) { break; }
// (回车) ' '(空格) (tab键)不显示的字符不算入 if (c != ' ' && c != ' ' && c != ' ' && c != ' ') { characterNum++; } } System.out.println("文件字符数为" + characterNum); in.close(); }
2. 计算行数,想过BufferReader的整行读取,但是,对于null的读取我解决不了, 作为最后一行也是读为null,单字符读写好像也有问题,我解决不了了。
public static void countRow(String s) throws Exception { FileReader in = new FileReader(s); int rowNum = 1; int r = in.read(); while (true) { // 接收的回车是 两个字节 if(r == ' ') { if (in.read() == ' ') { rowNum++; } } r = in.read(); if (r == -1) { break; } } System.out.println("文件行数为" + rowNum); in.close(); }
3. 计算单词数,对代码文件不太友好,毕竟连续的字母才算成一个单词,本意是 任何的除字母外特殊字符都具有分隔开单词的作用
public static void countWord(String s) throws Exception { FileReader in = new FileReader(s); int wordNum = 0; char nullChar = ' '; boolean flag = false; int w = in.read(); while (true) { // 单词只记录 标识,其他字符组成不算单词 boolean isWord = false; // 避免多个空格连续 while (w == nullChar) { w = in.read(); } //找到下一个空格前的都是同一个word t: while (w != nullChar && w != -1) { // 数字 不算单词 boolean wordForm = (w >= 'A' && w <= 'Z') || (w >= 'a' && w <= 'z') || w == '$' || w == '_'; if (wordForm) { if (!isWord) { isWord = true; } } else { w = in.read(); break t; } w = in.read(); } //读到文本末尾,如果前面是字母,那么+1. flag = isWord; //出来的条件不是文件末尾,且是空格 if (w != -1 && isWord) { wordNum++; } if (w == -1) { break; } } //worknum的计数是在遇到 空格、回车,计数前面连续的字符,若是最后读取-1,直接结束会漏掉一个 if (flag){ wordNum++; } System.out.println("文件单词数为" + wordNum); in.close(); }
4. 计算代码行、注释行、空行。通过一些boolean标志,先判断是否代码行,再看有没有出现 // 或 /* ,过程中计数可显示字符的个数,最后才根据标志和个数判断是否为空行
public static void countElse(String s) throws Exception { FileReader in = new FileReader(s); char nullChar = ' ', tabChar = ' ', rChar = ' '; int code = 0, empty = 0, note = 0, count; boolean isCode = false; boolean isNote = false; int t = in.read(); while (true) { // 第一个可显示字符 null_str = ' ' tab_char = ' ' while (t == nullChar || t == tabChar) { t = in.read(); } count = 0; // 非文尾 行末 while (t != rChar && t != -1) { // 代码行,标识、代码 都是字母 boolean judge1 = !isNote && !isCode && ((t >= 'A' && t <= 'Z') || (t >= 'a' && t <= 'z') || t == ';'); if (judge1) { code++; isCode = true; } // 数可显示字符 if (t != ' ' && t != ' ') { count++; } // 多行注释(/*)和单行注释(//) boolean judge2 = t == '/' && !isNote && ((t=in.read())=='/'|| t=='*'); if (judge2) { isNote = true; note++; } t = in.read(); } // while // 防止直接 回车空行 r_char=' ' if (t == rChar) { // 不大于1个可显示字符才算空行,且不是注释行,代码行 if (!isCode && !isNote && count <= 1) { empty++; }// 问题: count数到了注释行代表‘/’? // 未遇到 字母(代码行代表),注释行('/'代表) 这种 })特殊 else if (!isCode && !isNote) { code++; } // ' ' t = in.read(); //下一行开头 t = in.read(); } // 到下一行,初始化 isCode = false; isNote = false; // 到达这一步至少是 回车后-1 肯定空行 if (t == -1) { if(!isCode && !isNote) { empty++; } break; } } // true System.out.println("代码行数为" + code); System.out.println("空行数为" + empty); System.out.println("注释行数为" + note); in.close(); }
5. 路径转化,用了hashMap,将一个目录下的文件放到hashMap的value中,一步步将目录全部 listFiles(),文件跳过不需 listFiles(),直到集合末尾。
public static String[] Path(File f){ int dirNum = 0; int mapKey = 0; String[] realPath = new String[100]; HashMap<Integer,File> hash = new HashMap<Integer,File>(); File[] list = f.listFiles(); while(dirNum < list.length) { // 拿到输入 路径下的所有文件 hash.put(mapKey++, list[dirNum++]); } int count_dir = 0; int count ; int len = list.length; while (count_dir < len) { count = 0; File temp_file = hash.get(count_dir); if (temp_file.isDirectory()) { list = temp_file.listFiles(); len += list.length; while (count < list.length) { // 将该目录下的东西全部添加 hash.put(mapKey++, list[count++]); } } count_dir++; } int i =0 ,j=0; // 将hash中属于文件的拿出来作为路径 while(i<hash.size()) { if(!hash.get(i).isDirectory()) { realPath[j++] = hash.get(i).getPath(); } i++; } return realPath; }
六、测试运行(代码于IDEA上编写,图片于JVM运行)
1. -s对文件的操作,无法遍历
(1)文件输出结果
(2)文件如图,结果符合预期(可对*.c 、*.java 、*.txt 、其他后缀操作)
(1)文件输出结果如下
(2)文件如图
2. -s对目录的操作(支持绝大部分目录遍历,不要太在意文件的命名..)最下面有个计数文件数
(1)输出如下
(1)文件夹情况如下,通过运行,发现 “.class”文件的行数固定为1。不知道为什么,一些输出也很奇怪。对其他文件倒是正确
-x对文件,可执行多次,直至取消,对目录也可以使用,篇幅太长,不便多写。
七、PSP表格
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
15 |
·Estimate |
·估计这个任务需要多少时间 |
30 |
30 |
Development |
开发 |
1200 |
1380 |
·Analysis |
·需求分析 (包括学习新技术) |
120 |
150 |
·Design Spec |
·生成设计文档 |
20 |
30 |
·Design Review |
·设计复审(和同事审核设计文档) |
0 |
0 |
·Coding Standard |
·代码规范(为目前的开发指定合适的规范) |
30 |
60 |
·Design |
·具体设计 |
20 |
40 |
·Coding |
·具体编码 |
150 |
210 |
·Code Review |
·代码复审 |
30 |
20 |
·Test |
·测试(自我测试,修改代码,提交修改) |
120 |
180 |
Reporting |
报告 |
60 |
60 |
·Test Report |
·测试报告 |
30 |
30 |
·Size Measurement |
·计算工作量 |
10 |
10 |
·Postmortem & Process Improvement Plan |
事后总结,并提出过程改进计划 |
15 |
20 |
Total |
合计 |
1865 |
2235 |
八、总结
总的来说这次收获颇丰,熟悉了一些Java的知识,应用地更加灵活,但是自己在调试的时候遇到bug,感觉处理测试的时间太长了,处理不够科学严谨,很多很方便的工具也没用到。在整个过程中有进行过类似单元测试的过程,后来才知道正常流程是先测试代码再产品代码,还有,我的IDEA Plugins居然还没有Junit。总的来说,这个项目还没有到完备的阶段。后面我会继续自主学习TDD的知识和流程,并且对我这个WC修改。