结队项目
合作者:201631084236,201631062311
代码地址:https://gitee.com/ITtoto/group_wordcount20
本次作业的链接地址:https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188
PHP表格
PSP2.1 |
PSP阶段 |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
30 |
20 |
· Estimate |
· 估计这个任务需要多少时间 |
20 |
20 |
Development |
开发 |
400 |
600 |
· Analysis |
· 需求分析 (包括学习新技术) |
30 |
20 |
· Design Spec |
· 生成设计文档 |
0 |
0 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
60 |
30 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
30 |
10 |
· Design |
· 具体设计 |
60 |
80 |
· Coding |
· 具体编码 |
300 |
500 |
· Code Review |
· 代码复审 |
120 |
150 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
100 |
120 |
Reporting |
报告 |
120 |
40 |
· Test Report |
· 测试报告 |
30 |
20 |
· Size Measurement |
· 计算工作量 |
30 |
40 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
60 |
20 |
|
合计 |
1390 |
1690 |
代码互审情况
1.代码复审前
我们在分别测试了自己的部分,功能模块之后又自己的检查了自己和对方的工作环境和版本,最后保证准备工作都可以了才开始复审。
2.复审时
在代码复审时,每人拿出新的不同测试代码。仔细检查每个环节的可操作性,努力找出bug,每个人的代码多少会有一点小问题,不过在注意挑出之后就少很多,有些不能解决的就留下来接着讨论。
3.复审结果
我们最终都拿出了让我们满意的结果,让完整的代码打包。
设计过程
项目截图:
代码说明
UI界面:

1 package wc; 2 import java.awt.Container; 3 import java.awt.Point; 4 import java.awt.Toolkit; 5 import java.awt.event.ActionEvent; 6 import java.awt.event.ActionListener; 7 import java.io.BufferedReader; 8 import java.io.File; 9 import java.io.FileInputStream; 10 import java.io.IOException; 11 import java.io.InputStreamReader; 12 13 import javax.swing.JButton; 14 import javax.swing.JFileChooser; 15 import javax.swing.JFrame; 16 import javax.swing.JLabel; 17 import javax.swing.JTabbedPane; 18 import javax.swing.JTextField; 19 20 public class ChooseFile implements ActionListener { 21 JFrame frame = new JFrame("WordCount"); 22 JTabbedPane tabPane = new JTabbedPane();// 选项卡布局 23 Container con = new Container();// 布局1 24 JLabel label = new JLabel("选择文件"); 25 JTextField text = new JTextField(); 26 JButton button = new JButton("选择文件"); 27 JFileChooser jfc = new JFileChooser();// 文件选择 28 29 ChooseFile() { 30 jfc.setCurrentDirectory(new File("d:\\"));// 文件选择器的初始目录定为d盘 31 // 下面两行是取得屏幕的高度和宽度 32 double lx = Toolkit.getDefaultToolkit().getScreenSize().getWidth(); 33 double ly = Toolkit.getDefaultToolkit().getScreenSize().getHeight(); 34 frame.setLocation(new Point((int) (lx / 2) - 150, (int) (ly / 2) - 150));// 设定窗口出现位置 35 frame.setSize(500, 300);// 设定窗口大小 36 frame.setContentPane(tabPane);// 设置布局 37 // 下面设定标签等的出现位置和高宽 38 label.setBounds(40, 40, 150, 40); 39 text.setBounds(100, 40, 150, 40); 40 button.setBounds(280, 40, 150, 40); 41 button.addActionListener(this);// 添加事件处理 42 con.add(label); 43 con.add(text); 44 con.add(button); 45 con.add(jfc); 46 tabPane.add("文件选择", con);// 添加布局 47 frame.setLocationRelativeTo(null); 48 frame.setVisible(true);// 窗口可见 49 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 使能关闭窗口,结束程序 50 } 51 52 @Override 53 public void actionPerformed(ActionEvent e) {// 事件处理 54 if (e.getSource().equals(button)) { 55 // 初始化文件选择框 56 JFileChooser fDialog = new JFileChooser(); 57 // 设置文件选择框的标题 58 fDialog.setDialogTitle("请选择文件"); 59 // 弹出选择框 60 int returnVal = fDialog.showOpenDialog(null); 61 // 如果是选择了文件 62 if (JFileChooser.APPROVE_OPTION == returnVal) { 63 // 打印出文件的路径,你可以修改位 把路径值 写到 textField 中 64 text.setText(fDialog.getSelectedFile().getPath()); 65 66 } 67 ChooseFile cf = new ChooseFile(); 68 try { 69 cf.getFileContentAndPrint(fDialog.getSelectedFile().getPath()); 70 } catch (IOException e1) { 71 // TODO Auto-generated catch block 72 e1.printStackTrace(); 73 } 74 75 } 76 77 } 78 public void getFileContentAndPrint(String path) throws IOException { 79 int charNum = 0; 80 int wordNum = 0; 81 int lineNum = 0; 82 File file = new File(path); 83 if (file.exists() == false) { 84 file.createNewFile(); 85 } 86 InputStreamReader isr = new InputStreamReader(new FileInputStream(path)); 87 BufferedReader br = new BufferedReader(isr); 88 String str = null; 89 while ((str = br.readLine()) != null) { 90 charNum += str.length(); 91 wordNum += str.split(" ").length; 92 lineNum++; 93 } 94 System.out.println(file.getName() + ":"); 95 System.out.println("字符数:" + charNum); 96 System.out.println("单词数:" + wordNum); 97 System.out.println("行数:" + lineNum); 98 br.close(); 99 } 100 }
参数代码:

1 package wc; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.util.ArrayList; 6 7 import javax.swing.filechooser.FileSystemView; 8 9 public class DealParameter { 10 String[] input = null; 11 12 DealParameter(String[] input) { 13 this.input = input; 14 } 15 16 public void dealParameter() throws IOException {// 将用户输入的参数进行处理 17 // 单独处理-x参数 18 GetResult gr; 19 if (input.length == 1 && input[0].equals("-x")) { 20 new ChooseFile(); 21 22 } else { 23 24 String parentPath = null;// 获得上级文件路径 25 FileSystemView fsv = FileSystemView.getFileSystemView(); 26 File com=fsv.getHomeDirectory(); 27 parentPath = com.getPath(); 28 //File path = new File(".."); 29 // parentPath = path.getCanonicalPath(); 30 31 // 创建当前文件目录,用于有参数-s时得到当前目录下的文件 32 File currentFile = new File(parentPath); 33 if (currentFile.isDirectory() == false) { 34 System.out.println("currentFile is not a directory"); 35 System.exit(1); 36 } 37 38 ArrayList<String> choice = new ArrayList<String>();// 用于保存不同类型的参数 39 ArrayList<String> fileName = new ArrayList<String>();// 用于保存用户传入的参数中的所有的文件名 40 ArrayList<String> fileFormat = new ArrayList<String>();// 用于保存用户传入的参数中所有指定的通配符 41 ArrayList<File> aimFile = new ArrayList<File>();// 用于存储目录下的文件 42 43 boolean isExistFileFormat = false;// 用于标记是否有制定的统配符 44 for (String cell : input) {// 将参数分类 45 if (cell.startsWith("-")) { 46 choice.add(cell);// 保存带“-”的选项 47 } else if (cell.startsWith("*")) { 48 if (cell.equals("*.txt") || cell.equals("*.c") || cell.equals("*.java") || cell.equals("doc")) { 49 isExistFileFormat = true; 50 int begin = cell.indexOf("."); 51 String subString = cell.substring(begin); 52 fileFormat.add(subString);// 保存指定处理的文件格式,如:*.txt 53 } else { 54 System.out.println("通配符格式不正确"); 55 System.exit(1); 56 } 57 } else if (cell.endsWith(".txt") || cell.endsWith(".c") || cell.endsWith(".doc") 58 || cell.endsWith(".java")) { 59 fileName.add(cell);// 保存文件名 60 } else { 61 System.out.println("输入格式有误"); 62 System.exit(1); 63 } 64 } 65 boolean isExistS = false;// 用于判断是否有停用词表选项 66 boolean isExistE = false;// 用于判断是否有递归操作文件 67 // 如果有-s选项,则递归遍历当前目录下的所有非文件夹文件,并循环调用getFileContent()统计文件内容 68 for (String cell : choice) { 69 if (cell.equals("-s")) { 70 isExistS = true; 71 if (cell.equals("-e")) {// 是否停用词表 72 isExistE = true; 73 } 74 } 75 } 76 77 if (isExistS == true) {// 递归读取当前文件目录下的文件 78 File[] fileList = currentFile.listFiles();// 获得当前目录下的所有文件 79 80 for (File cell : fileList) { 81 82 if (isExistFileFormat == false && cell.isDirectory() == false) {// 没有指定处理的通配符 83 if (cell.getName().endsWith(".txt") || cell.getName().endsWith(".c") 84 || cell.getName().endsWith(".doc") || cell.getName().endsWith(".java")) { 85 aimFile.add(cell); 86 } 87 } else { // 如果有指定要处理的统配符 88 boolean isAimFile = false; 89 for (String format : fileFormat) { 90 if (cell.getName().endsWith(format)) { 91 isAimFile = true;// 如果是指定文件则标记为true 92 } 93 } 94 if (isAimFile == true && cell.isDirectory() == false) {// 判断是指定文件的话就装入集合中 95 if (cell.getName().endsWith(".txt") || cell.getName().endsWith(".c") 96 || cell.getName().endsWith(".doc") || cell.getName().endsWith(".java")) { 97 aimFile.add(cell); 98 } 99 } 100 } 101 } 102 for (File file : aimFile) { 103 104 if (isExistE == true && file.getName().equals(fileName.get(fileName.size() - 1))) {// 停用词表的文件统计 105 gr = new GetResult(); 106 if (fileName.size() == 2 || fileName.size() == 1) {// 如果有两个文件名,则表示用户指定输出文件 107 108 gr.outputFileName(fileName.get(0)); 109 } 110 gr.getFileContent(file.getAbsolutePath()); 111 System.out.println(file.getName() + ":");// 列出对应的文件名 112 for (String cell : choice) { 113 if (cell.equals("-c")) { 114 gr.dealChoices("c"); 115 } else if (cell.equals("-l")) { 116 gr.dealChoices("l"); 117 } else if (cell.equals("-a")) { 118 gr.dealChoices("a"); 119 } 120 } 121 } else {// 当前文件不是一个目录则可以进行统计 122 gr = new GetResult(); 123 if (fileName.size() >= 1) { 124 gr.outputFileName(fileName.get(0)); 125 } 126 gr.getFileContent(file.getAbsolutePath()); 127 System.out.println(file.getName() + ":"); 128 for (String cell : choice) { 129 if (cell.equals("-c")) { 130 gr.dealChoices("c"); 131 } else if (cell.equals("-w")) { 132 gr.dealChoices("w"); 133 } else if (cell.equals("-l")) { 134 gr.dealChoices("l"); 135 } else if (cell.equals("-a")) { 136 gr.dealChoices("a"); 137 } 138 } 139 } 140 } 141 } else { // 如果没有递归调用选项,则按一般的输入来处理 142 gr = new GetResult(); 143 if (fileName.size() == 2) {// 如果用户有输入指定输出的文件,则先调用outputfilename将文件名传入过去 144 gr.outputFileName(fileName.get(1)); 145 } 146 if (fileName.size() == 0) { 147 System.out.println("没有要统计的文件"); 148 System.exit(1); 149 } 150 gr.getFileContent(parentPath + "/" + fileName.get(0));// 传入统计的文件路径 151 System.out.println(fileName.get(0) + ":"); 152 for (String cell : choice) { 153 if (cell.equals("-c")) { 154 gr.dealChoices("c"); 155 } else if (cell.equals("-w")) { 156 gr.dealChoices("w"); 157 } else if (cell.equals("-l")) { 158 gr.dealChoices("l"); 159 } else if (cell.equals("-a")) { 160 gr.dealChoices("a"); 161 } 162 } 163 } 164 } 165 } 166 }
检测输入:

package wc; public class CheckInput { String[] input = null; CheckInput(String[] input) { this.input = input; } public boolean cheak() {// 检测用户输入是否合法 boolean pass = false;// 用于标记输入是否合法 for (String choice : input) { if (choice.startsWith("-")) { if (choice.length() != 2) { return false; } //int begin = choice.indexOf(1); String partOfChoice = choice.substring(1); switch (partOfChoice) { case "s": pass = true; break; case "a": pass = true; break; case "c": pass = true; break; case "l": pass = true; break; case "w": pass = true; break; case "x": if (input.length == 1) { pass = true; }else { System.out.println("-x 参数只能单独使用"); } break; case "e":// 检测-e选项是否搭配有-s选项和需要停用的词表 for (String cell : input) { if (cell.equals("-s")) { pass = true; break; }else { System.out.println("缺少参数-s"); return false; } } break; case "o": pass = true; break; default: System.out.println("选项格式不正确"); return false; } } else if (choice.startsWith("*")) {// 处理通配符的格式 boolean isExistS = false;// 因为通配符只能搭配-s使用 for (String cell : input) { if (cell.equals("-s")) { isExistS = true; break; } } if (isExistS == false) { System.out.println("缺少参数:-s"); return false; } if (choice.equals("*.txt") || choice.equals("*.c") || choice.equals("*.doc") || choice.equals(".java")) { pass = true; } else { System.out.println("通配符格式超出范围(格式范围:.txt/.java/.c/.doc)"); return false; } } else if (choice.endsWith(".txt")||choice.endsWith(".c")||choice.endsWith(".java")||choice.endsWith(".doc")) { pass = true; } else { System.out.println("非法输入"); return false; } } return pass; } }
统计结果:

1 public void getFileContent(String filePath) throws IOException {// 参数是要统计的文件路径,此方法用于打开文件并从文件中读取数据 2 charNum = 0; 3 wordNum = 0; 4 lineNum = 0; 5 blankLineNum = 0; 6 noteLineNum = 0; 7 codeLineNum = 0; 8 9 File file = new File(filePath); 10 if (file.exists() == false) {//需要统计的文件 11 System.out.println("the file to be counted don't exist!"); 12 System.exit(1); 13 } 14 InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath));// 获得文件内容 15 BufferedReader br = new BufferedReader(isr); 16 String s = null; 17 while ((s=br.readLine())!=null) { 18 19 char[] characters = null; 20 boolean isBlank = false; 21 boolean isNote = false; 22 if (s.length()==0) {// 判断是否是空行 23 blankLineNum++; 24 isBlank = true; 25 } 26 charNum += s.length();// 27 wordNum += s.split(" ").length; 28 lineNum++; 29 characters = s.toCharArray();//将读取的行转变成字符数组 30 for (int i = 0; i < characters.length; i++) { 31 if (characters[i] == '/' && characters[i + 1] == '/') {//判断是否是注释行 32 noteLineNum++; 33 isNote = true; 34 } 35 } 36 if(isBlank==false&&isNote==false) { 37 codeLineNum++; 38 } 39 40 } 41 br.close(); 42 }
输出到文件:

1 public void outputToFile(String result) throws IOException {//将结果输出到文件中 2 3 4 String filePath = null; 5 File file = new File(".."); 6 filePath = file.getAbsolutePath()+"/"+outputFileName; 7 File outputFile = new File(filePath); 8 if(outputFile.exists()==false) { 9 outputFile.createNewFile(); 10 } 11 FileWriter fw = new FileWriter(filePath,true);//以追加的方式写入文件 12 fw.write(result+"\n"); 13 fw.close(); 14 }
测试结果
总结
两个人的合作,你写你的功能,我写我的功能,不会的时候就互相讨论一下,以冲刺的方式做完这个小项目。其中的波折可谓是有点让人心烦的,有的时候一个返回值的问题就会困扰我们好长时间来一起研究,不过最终的结果是好的,我们成功的克服了所有摆在我们前面的小难点,算是深深的舒了一口气,因为我做UI做的比他的算法功能来的晚一点,所以时间上有点冲突,开始的时候分配有点问题,以为后面的部分比较多,所以我的部分相对来说少了一点,然后我们一起完善了功能和界面方面的东西,合代码的时候到不是很困难,毕竟项目不是很大,而且我们的思路也很明确,都知道哪个部分的注意事项。
整体来说第一次小组合作还是很成功的,感觉到了一点点未来工作的雏形,为自己以后工作打下了一个相对熟悉的工作环境,很有利于我们的未来发展,所以我觉得此次项目很有裨益。