软件工程第二次作业--文件读取

这个作业属于哪个课程2302软件工程
这个作业要求在哪里软件工程第二次作业–文件读取
这个作业的目标完成对世界游泳锦标赛跳水项目相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序
其他参考文献CSDN、《构建之法》、单元测试和回归测试

1.Gitcode项目地址


仓库地址: https://gitcode.net/qq_63574466/project-java

2. PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3030
• Estimate• 估计这个任务需要多少时间3030
Development开发13201540
• Analysis• 需求分析 (包括学习新技术)500540
• Design Spec• 生成设计文档6040
• Design Review• 设计复审6040
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)2030
• Design• 具体设计80180
• Coding• 具体编码300360
• Code Review• 代码复审6050
• Test• 测试(自我测试,修改代码,提交修改)240300
Reporting报告110105
• Test Repor• 测试报告6060
• Size Measurement• 计算工作量2015
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划3030
合计14601675

3.解题思路描述

1.Json数据的提取

在尝试网站提取后,最终决定使用来源于example/data文件夹内的Json数据
123

2.对Json数据解析

打开Json文件,查看需要提取的数据位置,
123
了解了json文件的树形结构,并知道了需要提取的数据所在位置,之后代码就可以按照编写。

通过修改results下比赛成绩Json文件的名称,可以在输入比赛项目时,直接通过比赛项目的名称进行查找。
文件名称的修改如下图所示:
women_10m_synchronised.json
123
这样的修改大大方便了json文件的查找

3. 代码组织思路

提取完成Json文件,并确定了Json文件的结构后,只需要根据输入的命令,从Json文件中提取出需要的数据,再进行输出即可。

  • 为此需要解析Json文件的工具类和文件操作的工具类。
  • 同时运动员和比赛成绩的两个实体类也是不可缺少的。
  • 为了能够满足输出格式,也需要输出远动员信息以及比赛成绩信息的关键函数。

4.设计与实现过程

1.代码的组织

首先确认了代码中包含2个实体类Player和Result、两个工具类FileUtil和JasonParseUtil、以及三个核心功能类GetJsonElement、PrintPlayers和PrintMatchResults。

  • JasonParseUtil中使用了谷歌的gson去解析json数据。
  • PrintPlayers和PrintMatchResults中的两个静态方法printPlayers和printMatchResults,分别是向输出文件中输出选手信息和比赛成绩。
  • GetJsonElement使用了Apache Commons IO的第三方库,使IO操作的代码变得更简单倾斜。

2.关键代码展示

GetJsonElement类,核心是getRootJasonElement方法,目的是为了从文件中获取根JasonElement

在代码中使用了Apache Commons IO的第三方库,与手动编写这些功能相比,实现方法的代码变得更小,更清晰,更易理解,大大方便了编程。

//从指定的文件中获得根JasonElement
public JsonElement getRootJasonElement(String inputFile) {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(inputFile);
        JsonElement jsonElement = null;

        jsonElement = readFileToJE(inputStream);
        return jsonElement;
    }
    //把指定的文件读取成JsonElement
    private JsonElement readFileToJE(InputStream inputStream){
        JsonElement jsonElement = null;
        if (inputStream != null) {
                String jsonString = readFileToString(inputStream);
                if (jsonString == null){
                    System.out.println("读取数据文件出错!");
                    return  jsonElement;
                }
                jsonElement = JsonParser.parseString(jsonString);
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

        } else {
            return null;
        }
        return jsonElement;
    }
    //把指定的文件读取成JsonElement
    private String readFileToString(InputStream inputStream){
        String jsonString = null;
        try {
            jsonString =IOUtils.toString(inputStream, StandardCharsets.UTF_8);
        }catch (IOException e){
            System.out.println("读取数据文件出错!");
        }
        return jsonString;
    }

PrintMatchResults类,主要目的是向文件中输出比赛成绩

    //向文件输出所有运动员的信息
    public static void printResults(String outputFile,String command){
        String event = command.toLowerCase().replaceFirst("result ", "").replace(" ", "_");
        String classPath = "data/results/" + event + ".json";
        GetJsonElement getJasonElement = new GetJsonElement();
        JsonElement jsonElement = getJasonElement.getRootJasonElement(classPath);
        List<Result> results = JsonParseUtil.parseFinalResult(jsonElement);
        FileUtil.append(outputFile,ResultListToString(results));
    }
    //将比赛成绩列表转化为字符串
    private static String ResultListToString(List<Result> results) {
        if (results == null || results.isEmpty()) {
            return "N/A\n-----";
        }
        StringBuilder builder = new StringBuilder();
        for (Result r : results) {
            builder.append(finalResult(r)).append("-----\n");
        }
        return builder.toString();
    }
    //将比赛成绩单个对象转变为字符串
    private static String finalResult(Result r){
        String finalScore =null;
        List<String> score = r.getFinalScore();
        if (score == null) {
            finalScore = "*\n";
            return
                    "Full Name:" + r.getFullName() + "\n" +
                            "Rank:" + r.getRank() + "\n" +
                            "Score=" + finalScore;
        }
        BigDecimal totalScore = score.stream()
                .map(BigDecimal::new)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        finalScore = score.stream()
                .collect(Collectors.joining(" + ", "", " = " + totalScore + "\n"));
        return
                "Full Name:" + r.getFullName() + "\n" +
                        "Rank:" + r.getRank() + "\n" +
                        "Score=" + finalScore;
    }

5.程序性能改进

5.1 对性能改进的分析

I/O流的重复操作会使代码重复率变高,同时也会影响程序的性能。输入流用FileReader会比较慢。

5.2 对性能的具体改进

使用BufferedReader去对输入流进行控制

List<String> lines = new ArrayList<>();
        try (InputStream is = new FileInputStream(file)) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }
        } catch (IOException e) {
            System.err.println("文件不存在或无法读取: " + e.getMessage());
        }

6.单元测试展示

测试采用java的Juit进行测试

对DWASearch.java的单元测试(主要对参数不同,与参数错误进行测试)

@org.junit.jupiter.api.Test
    void test1() {
        //错误的参数输入
        DWASearch.main(new String[]{"input"});
    }

    @org.junit.jupiter.api.Test
    void test2() {
        //input.txt内命令格式错误
        DWASearch.main(new String[]{"input.txt"});
    }

    @org.junit.jupiter.api.Test
    void test3() {
        //正确的只含players命令的input1.txt和output.txt
        DWASearch.main(new String[]{"input1.txt", "output.txt"});
    }

    @org.junit.jupiter.api.Test
    void test4() {
        //正确的只含players命令的input1.txt和output
        //output没有后缀但可正常写入
        DWASearch.main(new String[]{"input1.txt","output"});
    }

    @org.junit.jupiter.api.Test
    void test5() {
        //正确的只含players命令的input1.txt和output.6
        //output后缀为6但可正常写入
        DWASearch.main(new String[]{"input1.txt","output.6"});
    }

    @org.junit.jupiter.api.Test
    void test6() {
        //正确的只含result women 1m springboard命令的input1.txt和output.txt
        DWASearch.main(new String[]{"input2.txt","output.txt"});
    }

    @org.junit.jupiter.api.Test
    void test7() {
        //正确的含players和result women 1m springboard双命令的input1.txt和output.txt
        DWASearch.main(new String[]{"input3.txt","output.txt"});
    }

测试结果
1、对test1的测试
123
2.对test2的测试
123
3.对test3的测试
132
4.对test4的测试
123
5.对test5的测试
123
6.对test6的测试
123
7.对test7的测试
123

与预期相符

对接口函数的测试(主要对,各种不一样参数的输入进行判断)

    @org.junit.jupiter.api.Test
    void test_1() {
        //输出到output.txt
        PrintPlayers.printPlayers("output.txt");
    }

    @org.junit.jupiter.api.Test
    void test_2() {
        //错误的play命令,输出到output2.txt
        PrintMatchResults.printResults("output.txt2","play");
    }
    @org.junit.jupiter.api.Test
    void test_3() {
        //正确的players命令,输出到output3.txt
        PrintMatchResults.printResults("output.txt3","players");
    }

测试结果
1.对test_1的测试
123
2.对test_2的测试
123
3.对test_3的测试
123

与预期相符

思考如何优化覆盖率?

1.标识未覆盖的代码: 使用代码覆盖工具来分析测试用例,并标识哪些代码路径没有被覆盖到。这可以帮助专注于测试覆盖率较低的区域。
3.增加边界测试: 在测试用例中添加更多的边界条件,以确保代码在极端情况下仍然能够正确运行。
4.模拟异常情况: 确保测试用例包括对异常情况的测试,以验证代码在出现错误时的行为。
追踪分支覆盖率: 关注和追踪代码中的分支语句,确保每个分支都被测试到。这可以通过代码覆盖工具提供的分支覆盖率报告来实现。

7.心路历程与收获

我认为这次作业主要的难点在于对于json数据的解析、单元测试的编写、性能的提升、还有打包文件的过程。
尤其是打包时,因为使用了第三方库,所以打包时遇到了很多问题,在网上花费大量时间进行了很多搜索后,才找到具体的解决办法。
分析题目不难,但真正写起来时,却在Json数据的提取,以及文件读取检测、文件输入方面有很多不懂的地方。在网上的大量学习和请教下,终于完成了任务。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值