第一次作业:Word Count
1. 项目需求说明
刚拿到题目时,我先看了题目需求,并列出主要要实现的功能:
1. 读取文件内容
2. 计算字符数
3. 计算单词数
4. 计算行数
5. 向文件写入内容
经过主要的功能分析后,我决定用我比较熟悉的java语言来完成这个题目。
举例:
wc.exe –c file.c,则输出结果保存在result.txt中,内容格式如下(注意大小写):
file.c, 字符数: 50
wc.exe –w file.c,则输出结果保存在result.txt中,内容格式如下(注意大小写):
file.c, 单词数: 30
wc.exe –l file.c,则输出结果保存在result.txt中,内容格式如下(注意大小写):
file.c, 行数: 10
wc.exe –l –c file.c,则统计file.c中的字符数和行数,输出结果保存在result.txt中,内容格式如下:
file.c, 字符数: 50
file.c, 行数: 10
2. 编码过程
- PSP表格
**PSP2.1 ** | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 1 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 1 |
Development | 开发 | 170 | 535 |
· Analysis | · 需求分析 (包括学习新技术) | 10 | 5 |
· Design Spec | · 生成设计文档 | 30 | 40 |
· Design Review | · 设计复审 (和同事审核设计文档) | 10 | 0 |
· Coding | · 代码规范 (为目前的开发制定合适的规范) | 10 | 0 |
· Code Review | · 具体设计 | 10 | 5 |
· Test | · 具体编码 | 60 | 410 |
Reporting | · 代码复审 | 10 | 5 |
· Test Report | 报告 | 30 | 40 |
· Size Measurement | · 测试报告 | 30 | 10 |
· Postmortem & Process | · 计算工作量 | 5 | 10 |
Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 120 |
合计 | 210 | 650 |
- 小总结:
本次计划时间和实际花费的时间有很大的差异,从表格中可以分析出,
我在自己评估自己在具体编码的时间太乐观,这个项目看起来需求简单,
但由于我单java的字符IO流把握不是很熟悉,我也在使用正则表达式的
时候,出现了问题,导致在调试过程中花费了很多的时间。
其他也有出现偏差的地方,如:估计这个任务需要多少时间,
代码规范, 事后总结, 并提出过程改进计划等。由于我第一次通过
规范的软件设计过程的方法完成这次作业,对该过程缺少实践,所以
不能对时间把握的很好,希望能够在下一次做得更好。
2. 1 解题思路
我分析了用java语言完成该题目主要需要运用的知识是:文件的IO流部分的知识。
于是我复习了我自己学习java IO字符流模块的知识和笔记,相关笔记如下:
/*
------------| Reader 抽象类 输入字符流的基类
-----------------------| FileReader 读取文件的输入字符流
FileReader的步骤:
1. 找到目标文件
2. 建立数据输入字符流通道
3. 读取数据
*/
public class Demo1 {
public static void main(String[] args) throws IOException {
read1();
read2();
}
public static void read1() throws IOException {
File file = new File("E:/作业/Java/文件/b.txt");
FileReader fileReader = new FileReader(file);
int content = 0;
while((content = fileReader.read()) != -1){//每次读一个字符
System.out.print((char)content);
}
fileReader.close();
}
public static void read2() throws IOException {
File file = new File("E:/作业/Java/文件/b.txt");
FileReader fileReader = new FileReader(file);
//建立缓冲字符数组
char[] buf = new char[1024];
int length = 0;
while((length = fileReader.read(buf)) != -1)
{
System.out.println(new String(buf, 0, length));
}
}
}
/*
--------------| Write 抽象类 输出字符流的基类
--------------------------| FileWriter 向文件数据输出数据的输出字符流
FileWriter 的使用步骤:
1. 找到目标文件
2. 建立字符输出流通道
3. 输出数据
4. 关闭文件
注意:
1. filewriter底层维护了一个1024的字符数组,写的数据先存在该数组中,当调用flush或close方法或填满了数组才会保存到硬盘上。
2. new FileWriter(file); 如果目标文件不存在,会自动创建。
3. new FileWriter(file);默认先清空数据。如果要直接添加数据,使用FileWriter(File,true)。
*/
public class Demo2 {
public static void main(String[] args) throws IOException {
write();
}
public static void write() throws IOException {
File file = new File("E:/作业/Java/文件/b.txt");
FileWriter fileWriter = new FileWriter(file);
String data = "今天很开心";
fileWriter.write(data);
fileWriter.close();
}
}
然后,我又思考发现,在计算单词数的时候,可以通过正则表达式来截取字符串的方式计算单词数量,
所有我又复习了正则表达式的相关用法,相关示例如下:
范围词
[abc] 出现的只能是abc其中的一个
[^abc] 出现的只能是除了abc 的一个任意字符
[a-z1-9&$] 出现的只能是两头字母包括在内的字符(即:a~z 或1~9 或&或$)
2. 2 程序设计实现过程
在实际编码中,我使用了四个类,其类名和相关用途如下:
BaseCount:解析用户输入的命令行、调用JudgeOption类
相关方法:
wordCountMain()
BaseFunc:实现计算字符数、单词书、行数这三个方法
相关方法:
count_charsNum(String path)
count_wordsNum(String path)
count_linesNum(String path)
JudgeOption:判断用户输入参数,调用BaseFunc中对应的相关方法
相关方法:
judge(String arg, String readPath, String writePath)
WriteCount:把计算后的结果写出到指定文件
相关方法:
writeCount(String str, String path)
initFile(String path):如果写出的文件存在,将文件内容清空
2. 3 代码说明
BaseFunc 类
public class BaseFunc {
//计算字符数
public static int count_charsNum(String path){
int count = 0;
try {
FileReader fileReader = new FileReader(path);
char[] buf = new char[1024];
int length = 0;
while( (length = fileReader.read(buf)) != -1){
count += length;
}
fileReader.close();
} catch (Exception e) {
e.printStackTrace();
}
return count;
}
//计算单词数
public static int count_wordsNum(String path) {
int count = 0;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
while(br.read()!=-1)
{
String s = br.readLine();
for(int i=0; i<s.split("[^a-zA-Z]").length; i++){//通过非英文字符对字符串进行截取
if( !s.split("[^a-zA-Z]")[i].isEmpty()){//去掉两个连续非英文字符 所截取的空字符串
count ++;
}
}
}
br.close();
} catch (Exception e) {
System.out.println(e);
}
return count;
}
//计算行数
public static int count_linesNum(String path) {
int count = 0;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
while(br.read()!=-1)
{
String s = br.readLine();//每次读取一行,行数加一
count++;
}
br.close();
} catch (Exception e) {
System.out.println(e);
}
return count;
}
}
JudgeOption 类
public class JudgeOption {
//判断用户输入的参数,调用相关方法
public static void judge(String arg, String readPath, String writePath) {
int count = 0;
String str = "";
switch (arg) {
case "-c":
case "—c":
count = BaseFunc.count_charsNum(readPath);
str = readPath.split("/")[ (readPath.split("/").length-1) ];
str += ", 字符数:";
str += count;
WriteCount.writeCount(str, writePath);
break;
case "-w":
case "—w":
count = BaseFunc.count_wordsNum(readPath);
str = readPath.split("/")[ (readPath.split("/").length-1) ];
str += ", 单词数:";
str += count;
WriteCount.writeCount(str, writePath);
break;
case "-l":
case "—l":
count = BaseFunc.count_linesNum(readPath);
str = readPath.split("/")[ (readPath.split("/").length-1) ];
str += ", 行数:";
str += count;
WriteCount.writeCount(str, writePath);
break;
}
}
}
2. 4 测试设计过程
我总共设计了10个测试用例,其中7个为用户输入命令测试,3个为文件内容测试。
- 设计思路
对于用户输入命令的测试:由于我的主函数中有一行代码,即:用来调用我所有的项目方法,没有功能代码,因此可以确保其正确性。
其他所有函数中,若出现错误均将错误抛出,我使用MTest类来实现测试方法,当主程序中有异常抛出时,则捕捉并进行处理,即:输出异常,终止程序。
并添加代码:把预期结果用字符串数组保存,用if语句与实际结果判断,如果不符合,就assert(判断)
对于文件内容的测试,则需要手动将文件内容进行修改。
输入命令测试
-
wc.exe -c f.c
输出结果:
-
wc.exe -w f.c
输出结果:
-
wc.exe -l f.c
输出结果:
-
wc.exe -c -w -l f.c
输出结果:
-
wc.exe -s f.c
输出结果:
-
wc.exe
输出结果:
-
wc.exe -w f.txt
输出结果:
其中,f.c的内容如下:
count = BaseFunc.count_charsNum(readPath);
str = readPath.split("/")[ (readPath.split("/").length-1) ];
str += ", 字符数:";
str += count;
WriteCount.writeCount(str, writePath);
break;
文件内容测试
-
文件为空
结果:
-
文件1
aaaaaaaaa
结果:
- 文件2
public static void main(String[] args) {
String[] options = "-c -w -l src/file.c".split(" ");
// System.out.println(options.length);
/*for(int i=0; i<options.length; i++){
System.out.println(options[i]);
}*/
// wordCountMain(options);
wordCountMain(args);
}
结果:
其中,输入命令为:
wc.exe -c -w -l f.c
- - 测试代码如下:.
//该代码为判断程序是否出错的测试,而判断输出结果是否正确的测试代码这里不给出
public class MTest {
public void mtest(){
try {
ArrayList<String[]> list = new ArrayList<String[]>();
String[] options1 = "-c f.c".split(" ");
String[] options2 = "-w f.c".split(" ");
String[] options3 = "-l f.c".split(" ");
String[] options4 = "-c -w -l f.c".split(" ");
String[] options5 = "-s f.c".split(" ");
String[] options6 = " ".split(" ");
String[] options7 = "-w f.txt".split(" ");
list.add(options1);
list.add(options2);
list.add(options3);
list.add(options4);
list.add(options5);
list.add(options6);
list.add(options7);
for(int i=0; i<7; i++){
BaseCount.wordCountMain(list.get(i));
}
} catch (Exception e) {
System.out.println(e);
assert(false);
}
}
}
3. 总结反思:
通过这次完成WordCount作业的过程,我学到了很多:
1. 如何使用git对我的项目进行管理。
2. 如何使用博客,并写一篇自己的博文。
3. 复习、加深了对java字符IO流的使用。
4. 通过正则表达式的正确使用,可以帮我们轻松的编码,并实现自己想要的结果。
5. 如何通过Myeclipse来自动生成UML类图。
6. 如何使用将java程序导出为jar包,并转化为exe文件。
7. 如何编写设计一个测试用例
这项目实现的过程中也遇到了很多问题,但由于自己的坚持不懈,
通过在网上查询资料和同学的热心帮助将作业完成,并在作业的完成过程中不断的
反思和改进,使得自己在解决错误和问题中不断的提升。
4. 致谢
本次作业的顺利完成,主要参考老师提供的一些优秀的文章:
(地址:
https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
http://www.cnblogs.com/xinz/archive/2011/10/22/2220872.html
http://www.cnblogs.com/xinz/archive/2011/11/20/2255830.html
http://www.cnblogs.com/math/p/se-tools-001.html
)
和自己通过上网搜索到的一些参考资料:
(地址:
https://blog.csdn.net/limuzi13/article/details/52912625
https://blog.csdn.net/honjane/article/details/40739337
)
在此,对老师和上述资料的贡献者表示忠心的感谢。