项目相关要求

基本功能

支持 -c,查看文件的字符数(已实现)

支持 -w,查看文件的单词数(已实现)

支持 -l,查看文件的行数(已实现)

扩展功能

支持 -s 参数,递归处理目录下符合条件的文件。(已实现)

支持 -a 参数,返回更复杂的数据(代码行 / 空行 / 注释行)。(已实现)

高级功能

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

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

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

解题思路

通过main函数接收参数,然后根据参数调用相应的类方法,按参数中的文件路径读取文件,按行读取文件,使用正则表达式判断文件每一行中的单词数、字符数等信息累加,生成一个新的类来存放读取出来的文件的信息。最后,按要求打印信息。

遇到的困难及解决方法

困难描述:

使用Java的nio读取文件,如果文件包含中文会报错:

java.nio.charset.MalformedInputException: Input length = 1

使用Java的nio读取文件夹,如果文件夹中还有文件夹,读取会报错

做过哪些尝试:

修改文件读取时的编码方式为GBK:

BufferedReader reader = Files.newBufferedReader(path, Charset.forName("GBK"));

循环判断文件路径,如果是文件夹,拿出其中的文件路径,循环其中的文件夹,直到拿出所有的文件

public static ListlistSourceFiles(Path dir) {
Listresult = new ArrayList<>();
try (DirectoryStreamstream = Files.newDirectoryStream(dir)) {
for (Path entry: stream) {
if(Files.isDirectory(entry)){
ListinnerDir = listSourceFiles(entry);
result.addAll(innerDir);
}
else {
result.add(entry);
}
}
} catch (DirectoryIteratorException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}

是否解决:

经过以上两种方式,已解决问题。

有何收获:

提高了自己独立编程、思考的能力,自己写的代码,遇到困难会先想是哪里出了问题,如何解决,遇到JDK文档不能解决的,再上网查询资料。通过这次项目,也学习之前没有用过的nio的用法。

关键代码or设计说明

程序设计流程图如下:

软件工程软件工程用Java实现财务管理系统_正则表达式

文件读取的功能的实现代码主要在FileUtil类:(以下只显示关键代码)

//正则表达式用来判断代码行、空行
public static final Pattern commentLinePattern = Pattern.compile("^//.*$|^/\\*.*$|^\\*.*$|^\\*/.*$");
public static final Pattern blankLinePattern = Pattern.compile("[{}.,:]{1}");
public static MyFile singleFile(Path path) throws IOException {
//MyFile是一个用来带有文件单词数,字符数,行数等属性的对象
MyFile myFile = new MyFile();
myFile.setFileName(path.getFileName().toString());
StringBuilder fileMessage = new StringBuilder();
//使用BufferReader读取文件
BufferedReader reader = Files.newBufferedReader(path, Charset.forName(defaultCharsets[0]));
String line = null;
int lineNum = 0;
int charNum = 0;
int wordNum = 0;
int commentLine=0;
int blankLine = 0;
Matcher matcher = null;
while((line = reader.readLine())!=null){
//每读取一行行数加1
lineNum++;
String lineTemp = line.trim();
if(!lineTemp.isEmpty()){
//按单词的边界分离单词
String[] words = lineTemp.split("\\W+");
//这里的spilt方法可能会包含空的元素,要遍历判断后去掉
for(int i=0;i
if(!words[i].isEmpty()){
wordNum ++;
}
}
}
else{
//如果为空行,空行数量加1
blankLine++;
}
//去掉空格,即空格不算进字符里面,然后添加这行的字符数
charNum+=lineTemp.replaceAll(" ","").length();
//使用正则表达式匹配注释行
matcher = commentLinePattern.matcher(lineTemp);
if(matcher.matches()){commentLine++;}
//使用正则表达式匹配空行
matcher =blankLinePattern.matcher(lineTemp);
if(matcher.matches()){blankLine++;}
fileMessage.append(line+"\n");
}
myFile.setWordNum(wordNum);
myFile.setCharNum(charNum);
myFile.setLineNum(lineNum);
myFile.setBlankLineNum(blankLine);
myFile.setCommentLineNum(commentLine);
myFile.setCodeLineNum(lineNum-blankLine-commentLine);
reader.close();
myFile.setFileMessage(fileMessage.toString());
return myFile;
}

WordCalc.java类:根据main中传过来的参数,判断使用的方法:(以下只显示关键代码)

public void run(){
try{
switch(args[0]){
case "-c":
charCount(args[1]);
break;
case "-w":
wordCount(args[1]);
break;
case "-l":
lineCount(args[1]);
break;
case "-s":
countForSpecialFileName();
break;
case "-a":
moreMessageCount(args[1]);
break;
default:
error();
}
} catch (Exception e){
error();
e.printStackTrace();
}
}
View.java:生成图像界面的类(以下只显示关键代码)
public void actionPerformed(ActionEvent e) {
//Handle open button action.
if (e.getSource() == openButton) {
final JFileChooser fc = new JFileChooser();
int returnVal = fc.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
//This is where a real application would open the file.
try {
//处理文件的路径,把文件路径中包含的java的特殊字符'\'替换为'\\',然后调用FileUtil类处理文件
List fileList = FileUtil.readFile(file.getAbsolutePath().replaceAll("\\\\","\\\\\\\\"));
MyFile f = fileList.get(0);
//输出文件的信息
text.append(f.getFileName()+" Message:\n");
text.append("CharNumber: " + f.getCharNum());
text.append(" WordNumber: " + f.getWordNum());
text.append(" LineNumber: " + f.getLineNum());
text.append(" BlankLineNumber: " + f.getBlankLineNum());
text.append(" CommentLineNumber: " + f.getCommentLineNum());
text.append(" CodeLineNumber: "+ f.getCodeLineNum()+newline);
} catch (IOException e1) {
e1.printStackTrace();
}
} else {
text.append("Open command cancelled by user." + newline);
}
}
}

测试运行

处理-x参数:

软件工程软件工程用Java实现财务管理系统_软件工程 java实现_02

软件工程软件工程用Java实现财务管理系统_软件工程 java实现_03

处理-a参数:

软件工程软件工程用Java实现财务管理系统_读取文件_04

处理-s参数:

软件工程软件工程用Java实现财务管理系统_文件路径_05

PSP表格

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

5

10

· Estimate

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

5

10

Development

开发

290

670

· Analysis

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

30

180

· Design Spec

· 生成设计文档

30

30

· Design Review

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

10

30

· Coding Standard

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

10

10

· Design

· 具体设计

30

60

· Coding

· 具体编码

120

300

· Code Review

· 代码复审

30

30

· Test

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

30

30

Reporting

报告

65

80

· Test Report

· 测试报告

30

30

· Size Measurement

· 计算工作量

5

10

· Postmortem & Process Improvement Plan

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

30

40

合计

360

760

项目小结

从这个项目我发现我的Java基础知识掌握的并不好,设计的代码略显冗余,而且代码的可扩展性不高,不过通过本次项目,我遇到问题懂得先自己去官方文档中查找答案,而不是之前去百度找别人的代码。当然,代码测试方面我还做的不够好,仅仅进行了回归测试,对于java类中的方法没有进行单元测试,这是我还需要加强的地方。