扩大
缩小
jQuery火箭图标返回顶部代码 - 站长素材

软工实践寒假作业(2/2)

这个作业属于哪个课程 2020春丨S班 (福州大学)
这个作业要求在哪里 要求
这个作业的目标 开发疫情统计程序,学习GitHub
作业正文 软工实践寒假作业(2/2)
其他参考文献 Java菜鸟教程助教资料

1、GitHub仓库地址

   https://github.com/rzm-A/InfectStatistic-main

2、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30min 30min
Estimate 估计这个任务需要多少时间 30min 30min
Development 开发 60min 60min
Analysis 需求分析 (包括学习新技术) 200min 200min
Design Spec 生成设计文档 60min 60min
Design Review 设计复审 100min 100min
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60min 60min
Design 具体设计 30min 30min
Coding 具体编码 300min 300min
Code Review 代码复审 200min 200min
Test 测试(自我测试,修改代码,提交修改) 200min 200min
Reporting 报告 30min 30min
Test Repor 测试报告 30min 30min
Size Measurement 计算工作量 30min 30min
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 150min 160min
合计 1510min 1520min

3、解题思路描述

程序主要功能:命令行参数处理、日志文件处理、输出结果
  • 命令行参数处理
    $ java InfectStatistic list -date 2020-01-22 -log D:/log/ -out D:/output.txt
    list命令 支持以下命令行参数:
    • -log 指定日志目录的位置,该项必会附带,请直接使用传入的路径,而不是自己设置路径
    • -out 指定输出文件路径和文件名,该项必会附带,请直接使用传入的路径,而不是自己设置路径
    • -date 指定日期,不设置则默认为所提供日志最新的一天。你需要确保你处理了指定日期以及之前的所有log文件
    • -type 可选择[ip: infection patients 感染患者,sp: suspected patients 疑似患者,cure:治愈 ,dead:死亡患者],使用缩写选择,如 -type ip 表示只列出感染患者的情况,-type sp cure则会按顺序【sp, cure】列出疑似患者和治愈患者的情况,不指定该项默认会列出所有情况。
    • -province 指定列出的省,如-province 福建,则只列出福建,-province 全国 浙江则只会列出全国、浙江
      对读取的参数进行检验,并且使用类InfectStatistic的成员变量保存部分参数以便后续调用。
  • 日志文件处理
    读取log指定的日志文件,根据日志统计全国及各省的感染患者、疑似患者、治愈和死亡人数
    日志数据形式:
    • <省> 新增 感染患者 n人
    • <省> 新增 疑似患者 n人
    • <省1> 感染患者 流入 <省2> n人
    • <省1> 疑似患者 流入 <省2> n人
    • <省> 疑似患者 确诊感染 n人
    • <省> 死亡 n人
    • <省> 治愈 n人
    • <省> 排除 疑似患者 n人
      关于文件读取,所有日期先于date的都需读取处理,因为按日期处理数据,在计算过程可能出现负数
  • 输出结果
    将处理结果输出至out指定的输出文件,根据type与province参数选择部分数据进行输出,采用数据结构HashMap

4、设计实现过程

logo_1

5、代码说明

  • 命令行参数处理
    //验证命令行传入参数的正误,初始化文件路径等
    public static boolean Verify_Init_args(String[] args_) throws IOException {
    	if(args_[0].equals("list")){
    		for (int i = 1; i < args_.length; i++) {
    			i++;
    			switch (args_[i-1]) {
					case "-date":
						date_p = new String(args_[i]);
	                    break;
    				case "-log":
    					log_p = args_[i];
    					File file = new File(log_p);
    			        if (!file.exists()) {
    			        	System.out.print("-log错误!--");
    			        	return false;
    			        }
                        break;
    				case "-out":
    					out_p = args_[i];
                        break;
    				case "-type":
    					AllType = true;
    					for(int j = 0;!args_[i].startsWith("-");j++,i++) {
    						if(!typeMap.containsKey(args_[i])) {
    							System.out.print("-type错误!--");
    							return false;
    						}
    						else
    							type_p[j] = typeMap.get(args_[i]);
    					}
    					i--;
                        break;
    				case "-province":
    					AllProvince = false;
    					for(int j = 0;i < args_.length && !args_[i].startsWith("-");j++,i++){
    						if(provinceList.contains(args_[i])) {
    							province_p.add(args_[i]);
    						}
    						else
    							System.out.print("-province错误!--");
    					}
    					i--;
                        break;
    				default:
                            return false;
                }
            }
    		return true;
        }
    	return false;
    }
  • 日志文件处理
    主要处理步骤:选取符合格式的.txt日志,打开日志逐行处理文件
    //验证文件是否存在,不存在返回false,存在则读取处理文件数据返回true
    @SuppressWarnings("null")
	public boolean Read_Deal_File() throws IOException {  
    	boolean b = false;
        String filename;
        String[] filedate;
        String[] name = new String[100];
        int[] num = new int[100];
        int i,j;
        File file = new File(log_p);
        File[] tempList = file.listFiles();
        //选取符合命名的文件
        for(i=0,j = 0;i < tempList.length;i++) {
        	filename = new String(tempList[i].getName());
	        filedate = filename.split("\\.");
	        boolean b1,b2,b3,b4;
	        if(filedate[0].length() != 10)
	        	continue;
	        if(filedate[0].charAt(4) != '-' || filedate[0].charAt(7) != '-')
	        	continue;
	        b1 = Date_Isdit(filedate[0],0,1);
	        b2 = Date_Isdit(filedate[0],2,3);
	        b3 = Date_Isdit(filedate[0],5,6);
	        b4 = Date_Isdit(filedate[0],8,9);
	        if(b1 && b2 && b3 && b4 && filedate[0] !=null) {
	        	name[j] = filedate[0];
	        	num[j++] = i;
	        }
        }
        //读取处理log.txt文件
        for(i = 0;i < j;i++) {
        	if(date_p.compareTo(name[i]) >= 0) {
        		BufferedReader br = null;               
                String dates = null;
                br = new BufferedReader(new InputStreamReader(new FileInputStream(tempList[num[i]].toString()), "UTF-8"));  
                while ((dates = br.readLine()) != null){
                	Deal_Dates_Line(dates); 
                }
                b = true;
                br.close();
        	}
        }
        //对每个日志文件,统计全国信息
        map.put(provinceList.get(0), new Province(provinceList.get(0)));
        for (i = 0; i < provinceList.size(); i ++ ){
            if (map.get(provinceList.get(i)) != null)
            	map.get(provinceList.get(0)).Statistics(map.get(provinceList.get(i)));
        }
        return b;
    }
    //检验是否是数字
    private boolean Date_Isdit(String str,int num1,int num2) {
    	if(!Character.isDigit(str.charAt(num1)) || !Character.isDigit(str.charAt(num2))) {
        	return false;
        }
    	return true;
    }
    //处理文件数据(单行)
    private void Deal_Dates_Line(String dates) throws IOException {
    	String[] date = dates.split(" ");
        if (map.get(date[0]) == null)
            map.put(date[0], new Province(date[0]));
        else if (date[0].equals("//"))
	        return;
        
        switch(date[1])
        {
            case "新增":
                if (date[2].equals("感染患者"))
                    map.get(date[0]).add_Ip(date[3]);
                else
                    map.get(date[0]).add_Sp(date[3]);
                break;
            case "感染患者":
                if (map.get(date[3]) == null)
                    map.put(date[3], new Province(date[3]));
                map.get(date[3]).add_Ip(date[4]);
                map.get(date[0]).reduce_Ip(date[4]);
                break;
            case "疑似患者":
                if (date[2].equals("流入")){
                    if (map.get(date[3]) == null)
                        map.put(date[3], new Province(date[3]));
                    map.get(date[3]).add_Sp(date[4]);
                    map.get(date[0]).reduce_Sp(date[4]);
                }
                else{
                    map.get(date[0]).add_Ip(date[3]);
                    map.get(date[0]).reduce_Sp(date[3]);
                }
                break;
	        case "死亡":
	        	map.get(date[0]).reduce_Ip(date[2]);
	            map.get(date[0]).dead(date[2]);
	            break;
	        case "治愈":
	        	map.get(date[0]).reduce_Ip(date[2]);
	            map.get(date[0]).cure(date[2]);
	            break;
	        case "排除":
	            map.get(date[0]).reduce_Sp(date[3]);
	            break;
            default:
                break;
        }
    }
  • 输出结果
    //根据要求生成输出文件
    public void Output_File() throws IOException {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(out_p), "UTF-8"));
        //无-province参数,默认输出所有省情况
        if (AllProvince)
        {
            for (int i = 0;i < provinceList.size();i++)
                if (map.get(provinceList.get(i)) != null)
                    map.get(provinceList.get(i)).output(AllType,type_p ,bw);
        }
        else
        {
            for (int i = 0; i < provinceList.size(); i ++ )
                if (province_p.contains(provinceList.get(i)))
                    map.get(provinceList.get(i)).output(AllType,type_p ,bw);
        }
        bw.write("// 该文档并非真实数据,仅供测试使用");
        bw.close();
    }
  • 其他
    Class Province 保存一个省的具体数据,提供根据文件数据进行修改的方法
    //某个省份的具体数据
    class Province {
	//省份名称
	private String provincename;
	//疑似患者人数
	private int sp;
	//感染患者人数
	private int ip;
	//治愈人数
	private int cure;
	//死亡人数
	private int dead;
	
	//构造函数
	public Province(String provincename){
		this.provincename = provincename;
		sp = 0;
		ip = 0;
		cure = 0;
		dead = 0;
	}
	
	//感染患者增加
	public void add_Ip(String str){
		ip += Integer.parseInt(str.substring(0, str.length()-1));
	}
		
	//疑似患者增加
	public void add_Sp(String str){
	    sp += Integer.parseInt(str.substring(0, str.length()-1));
	}

	//感染患者减少
	public void reduce_Ip(String str){
	    ip -= Integer.parseInt(str.substring(0, str.length()-1));
	}
	
	//疑似患者减少
	public void reduce_Sp(String str){
	    sp -= Integer.parseInt(str.substring(0, str.length()-1));
	}
	
	//死亡
	public void dead(String str){
		dead += Integer.parseInt(str.substring(0, str.length()-1));
	}  
	
	//治愈
	public void cure(String str){
		cure += Integer.parseInt(str.substring(0, str.length()-1));
	}
	
	//统计全国数据
	public void Statistics(Province p){
	    this.ip += p.ip;
	    this.sp += p.sp;
	    this.cure += p.cure;
	    this.dead += p.dead;
	}

	//输出指定省的信息
	public void output(boolean alltype, String[] type, BufferedWriter bw) throws IOException{
	    //无-type参数,默认输出所有type类型
	    if (alltype){
	        bw.write(provincename+ " 感染患者 " +ip+ "人 疑似患者 " +sp+ "人  治愈 " 
	        		+cure+ "人 死亡 " +dead+ "人");
	        bw.newLine();
	    }
	    else
	      {
	          bw.write(provincename);
	          for (int i = 0; i < type.length; i ++ ){
	        	  bw.write(" " +type[i]);
	        	  switch (type[i])
	              {
	        	  	case "感染患者":                  
	                    bw.write(ip+ "人");           
	                    break;
	                case "疑似患者":                  
	                    bw.write(sp+ "人");               
	                    break;
	                case "治愈":                    
	                    bw.write(cure+ "人");                  
                        break;
                    case "死亡":                    
                        bw.write(dead+ "人");          
                        break;
                    default:                
                        break;
	                }
	          }
	          bw.newLine();
	      }       
	  }
}

6、单元测试截图和描述

  • 命令行参数处理
    便于测试,这边直接在main()中传入命令行参数,并使用System.out.println()查看
    //main()方法中
    String[] aa= {"list", "-date","2020-01-27","-log" ,"C:\\Users\\东伯\\Desktop\\123","-out","D:\\ouput.txt","-type","ip","cure","-province","全国","福建","湖北"};
    if (!Verify_Init_args(aa)) {
    	System.out.println("参数错误 ");
    	return ;
    }
    //Verify_Init_args()方法中,在返回结果前填加以下代码,其他参数也可如此检验
    System.out.println("date = " +date_p);

   运行结果:
logo_6_1

  • 日志文件处理
    //Read_Deal_File()方法中
    System.out.println("循环处理log.txt");
    for(i = 0;i < j;i++) {
        if(date_p.compareTo(name[i]) >= 0) {
            System.out.println(i+ " 文件名:" +name[i]);
            ...
        }
    }

   运行结果:
logo_6_2

  • 输出结果
    运行结果
    logo_6_3
       注意,若不指定type则输出全部类型,若不指定province则输出全国与全部省

7、单元测试覆盖率优化和性能测试,性能优化截图和描述

  • 单元测试覆盖率
    logo_7_1
  • 性能测试
    logo_7_2
  • 性能优化
    • 文件名检查:选取符合要求的函数写的过于粗糙简陋。
    • ...

8、代码规范的链接

   codestyle

9、心路历程与收获

9.1 心路历程

   乍一看,这啥呀,完全看不懂!然后慢慢的分析研究,感觉代码部分还是相对比较简单的,麻烦的是博客的编写。

9.2 收获

  • 巩固了GitHub知识
  • 复习了Java知识
  • 学会了eclipse单元测试的方法和性能测试方法
  • ...

10、 技术路线图相关的5个仓库

1、Java
链接:https://github.com/rzm-A/Java
简介:涵盖Java基础知识,详细讲解了Java编程中常用的API
2、JAVAWeb-Project
链接:https://github.com/rzm-A/JAVAWeb-Project
简介:初学JAVA-WEB开发的小项目💖
3、Linux
链接:https://github.com/rzm-A/linux
简介:Linux kernel source tree
4、Linux-Tutorial
链接:https://github.com/rzm-A/Linux-Tutorial
简介:Java 程序员眼中的 Linux
5、tldr.linux.cn
链接:https://github.com/rzm-A/tldr.linux.cn
简介:Linux 命令快速查询(Linux 小程序 Web 版)

posted @ 2020-02-21 13:17  一只东伯  阅读(128)  评论(0编辑  收藏  举报