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

222100128黄煦陶 2024-03-02 15:53:02
这个作业属于哪个课程<2302软件工程社区>
这个作业要求在哪里<软件工程第二次作业——文件读取>
这个作业的目标<完成对世界游泳锦标赛跳水项目相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序>
其他参考文献《码出高效_阿里巴巴java开发手册》单元测试和回归测试工程师的能力评估和发展

目录

  • Gitcode项目地址
  • PSP表格
  • 解题思路描述
  • 问题1:了解JSON文件格式及其解析方法
  • 问题2:实现功能的思路
  • 接口设计和实现过程
  • 关键代码展示
  • 性能改进
  • 单元测试
  • 异常处理
  • 心得体会

Gitcode项目地址

仓库地址

PSP表格

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

解题思路描述

助教提供了从游泳比赛官网上爬取完成的比赛信息(json形式),主要任务分为两步:1.解析json字符串获取所需要的信息 2.完成各个查询功能的实现

问题1:了解JSON文件格式及其解析方法

以前对JSON没有具体学习过,所以对于JSON文件的格式以及解析方法没有知识积累,查资料获知Java中解析JSON数据通常使用第三方库,比较常用的有Jackson、Gson和Org.json等,在此采用Org.json

问题2:实现功能的思路

带着功能需求阅读助教提供的athletes.json文件,可以筛选出需要解析的信息

在这里插入图片描述


由图片可见athletes.json文件是一个Object对象数组,每个Object对象用来储存某个国家的信息以及该国家所有参赛运动员信息,运动员信息存储在"Participaions"下的另一个Object对象数组中,这个对象数组中的每个Object都存储着某一位运动员的个人信息,
要实现输出每个运动员的信息,就要从这里开始下手,每个Object对象里的"Gender"字符串对应该运动员的性别,"PreferredLastName"和"PreferredFirstName"对应运动员的

接下来看results文件夹中的json文件解析

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


可以看到该json文件包含一个大的Object对象,对象中"DisciplineName"即为比赛项目名称,对象中"Heats"字符串下的Object对象数组中存储的是比赛结果数据。
对象数组中的"Results"字符串中又包含有一个Object对象数组,该数组中的对象是每名运动员在决赛中的成绩数据。在该对象数组下的"Rank"字符串存储着运动员的名次信息,"FullName"字符串存储着运动员的姓名信息。以上就是我们需要提取的所有数据元素。

接口设计和实现过程

根据程序设计需求,我将各个功能封装成函数,方便后续使用。大部分函数都封装在Lib类中,方便主程序直接通过函数接口进行调用以及进行单元测试。

  1. readAndPrintFile()用于读取input.txt文件中的所有数据

  2. getResult()函数用于识别input.txt文件中的指令类型以及错误的输入格式,输入正确则返回正确的指令,输入不正确则调用getError()传输相应的错误("N/A" 或 "error")信息到outputToFile()打印到output.txt文件

  3. outputToFile()用于根据命令不同输出所需数据到output.txt

  4. getPlayers()用于读取athletes.json文件中的所有运动员数据,并存储到class Athlete(运动员类)中去,然后输出所有运动员信息到output.txt。在运行过程中会调用getJsonObject()函数获取json对象,并用.getString将所需属性据转换成相应String字符串。

  5. getWomen1mSpringboard()等用于读取某场赛事文件中的运动员数据,并存储到class Athlete(运动员类)中去,然后输出运动员信息以及比赛结果到output.txt。

关键代码展示

class Athlete 运动员类

class Athlete implements Comparable<Athlete> {
    private String fullName;//名字
    private String gender;//性别
    private String country;//国籍
    private String rank;//排名
    private String score;//决赛分数
    private String preliminary;//初赛分数
    private String semifinal;//半决赛分数
    private String finals;//总决赛分数



    public Athlete(String fullName, String gender, String country) {
        this.fullName = fullName;
        this.gender = gender;
        this.country = country;
    }

    public Athlete(String fullName, String gender, String rank, String score) {
        this.fullName = fullName;
        this.gender = gender;
        this.rank = rank;
        this.score = score;
    }


    public Athlete(String fullName, String rank, String preliminary, String semifinal, String finals) {
        this.fullName = fullName;
        this.rank = rank;
        this.preliminary = preliminary;
        this.semifinal = semifinal;
        this.finals = finals;
    }


    public String getFullName() {
        return fullName;
    }

    public String getGender() {
        return gender;
    }

    public String getCountry() {
        return country;
    }

    public String getRank() {
        return rank;
    }

    public String getScore() {
        return score;
    }

    public String getPreliminary() {
        return preliminary;
    }

    public String getSemifinal() {
        return semifinal;
    }

    public String getFinals() {
        return finals;
    }

    @Override
    public String toString() {
        return "Athlete{" +
                "fullName='" + fullName + '\'' +
                ", rank='" + rank + '\'' +
                ", preliminary='" + preliminary + '\'' +
                ", semifinal='" + semifinal + '\'' +
                ", finals='" + finals + '\'' +
                '}';
    }

    @Override
    public int compareTo(Athlete other) {
        // 先按照国籍进行升序排序
        int countryNameComparison = this.country.compareTo(other.country);
        if (countryNameComparison != 0) {
            return countryNameComparison;
        }

        // 如果国籍相同,则按照lastName进行升序排序
        return this.fullName.compareTo(other.fullName);
    }
}

getPlayers()

//集合所有运动员信息 1
    public  void getPlayers(String name){
        List<Athlete> athletes = null;
        try {
            // 读取JSON文件内容
            String jsonData = new String(Files.readAllBytes(Paths.get("src/data/athletes.json")));

            // 解析JSON数据
            JSONArray athletesArray = new JSONArray(jsonData);

            // 创建运动员列表
            athletes = new ArrayList<>();

            // 遍历每个运动员
            for (int i = 0; i < athletesArray.length(); i++) {
                JSONObject athleteObj = athletesArray.getJSONObject(i);
                JSONArray participations = athleteObj.getJSONArray("Participations");

                for (int j = 0; j < participations.length(); j++){
                    JSONObject participation = participations.getJSONObject(j);
                    String lastName = participation.getString("PreferredLastName");
                    String firstName = participation.getString("PreferredFirstName");
                    String fullName = lastName + " " + firstName;
                    String gender = participation.getInt("Gender") == 0 ? "Male" : "Female";
                    String country = participation.getString("NAT");
                    // 创建运动员对象并添加到列表
                    Athlete athlete = new Athlete(fullName, gender, country);
                    athletes.add(athlete);
                }

            }

            // 对运动员列表进行排序
            Collections.sort(athletes);

            //将数据写入input.txt文件中
            outputToFile("src/data/output.txt", athletes, name);


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

getWomen1mSpringboard()等,以getWomen1mSpringboard()为例,其他的函数类似

 //集合Women 1m Springboard运动员信息 2
    public void getWomen1mSpringboard(String name){
        List<Athlete> athletes = new ArrayList<>();
        List<Athlete> athletes1 = new ArrayList<>();
        try {
            // 读取JSON文件内容
            String jsonContent = new String(Files.readAllBytes(Paths.get("src/data/108c795d-5e4f-4dc6-acea-0bc70bfd1928.json")));

            // 解析JSON
            JSONObject jsonObject = new JSONObject(jsonContent);
            JSONArray heatsArray = jsonObject.getJSONArray("Heats");

            //只需要决赛信息
            if (name.equals("result women 1m springboard")){
                JSONObject heatObject = heatsArray.getJSONObject(0);
                JSONArray resultsArray = heatObject.getJSONArray("Results");

                // 遍历Results数组
                for (int j = 0; j < resultsArray.length(); j++) {
                    JSONObject resultObject = resultsArray.getJSONObject(j);
                    JSONArray dives = resultObject.getJSONArray("Dives");
                    StringBuilder divePoints = new StringBuilder();
                    double total = 0.0;
                    for (int t = 0; t < dives.length(); t++){
                        double dp = dives.getJSONObject(t).getDouble("DivePoints");
                        total += dp;
                        String divePoints1 = null;
                        if (dp == 0.00){
                            divePoints1 = "0.00";
                        }else {
                            divePoints1 = df.format(dp);
                        }
                        if (t < dives.length() - 1){
                            divePoints.append(divePoints1 + " " + "+" + " ");
                        }else{
                            divePoints.append(divePoints1 + " ");
                        }
                        if (t == dives.length() - 1){
                            divePoints.append("=" + " " + df.format(total));
                        }
                    }

                    String rank = String.valueOf(resultObject.getInt("Rank"));
                    String fullName = resultObject.getString("FullName");
                    Athlete athlete = new Athlete(fullName, null, rank, String.valueOf(divePoints));
                    athletes.add(athlete);
                }
                outputToFile("src/data/output.txt", athletes, name);
            }

            //初赛,决赛信息
            if (name.equals("result women 1m springboard detail")){
                for(int i = heatsArray.length() - 1; i >= 0; i--){
                    JSONObject heatObject = heatsArray.getJSONObject(i);
                    JSONArray resultsArray = heatObject.getJSONArray("Results");

                    // 遍历Results数组
                    for (int j = 0; j < resultsArray.length(); j++) {
                        JSONObject resultObject = resultsArray.getJSONObject(j);
                        JSONArray dives = resultObject.getJSONArray("Dives");
                        StringBuilder divePoints = new StringBuilder();
                        double total = 0.0;
                        for (int t = 0; t < dives.length(); t++){
                            double dp = dives.getJSONObject(t).getDouble("DivePoints");
                            String divePoints1 = null;
                            if (dp == 0.00){
                                divePoints1 = "0.00";
                            }else {
                                divePoints1 = df.format(dp);
                            }
                            total += dp;
                            if (t < dives.length() - 1){
                                divePoints.append(divePoints1 + " " + "+" + " ");
                            }else{
                                divePoints.append(divePoints1 + " ");
                            }
                            if (t == dives.length() - 1){
                                divePoints.append("=" + " " + df.format(total));
                            }
                        }

                        String rank = String.valueOf(resultObject.getInt("Rank"));
                        String fullName = resultObject.getString("FullName");
                        Athlete athlete = new Athlete(fullName, null, rank, String.valueOf(divePoints));
                        athletes.add(athlete);
                    }
                }

                //集合初赛,半决赛,总决赛成绩
                HashMap<String, List<Athlete>> listScore = getListScore(athletes);

                // 打印整合后的对象
                for (Map.Entry<String, List<Athlete>> entry : listScore.entrySet()) {

                    if (entry.getValue().size() == 1){
                        String rank = entry.getValue().get(0).getRank() + " | * | *";
                        Athlete athlete = new Athlete(entry.getKey(), rank, entry.getValue().get(0).getScore(), "*", "*");
                        athletes1.add(athlete);
                    }
                    if (entry.getValue().size() == 2){
                        String rank = entry.getValue().get(0).getRank() + " | * | " + entry.getValue().get(1).getRank();
                        Athlete athlete = new Athlete(entry.getKey(), rank, entry.getValue().get(0).getScore(), entry.getValue().get(1).getScore(), "*");
                        athletes1.add(athlete);
                    }
                }
                //将数据写入output.txt文件
                outputToFile("src/data/output.txt", athletes1, name);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

在这里插入图片描述

性能改进

在最初设计程序时,采用FileWriter和FileReader来对文件进行读写,后面与同学交流了解到可以使用BufferWriter和BufferReader来进行替代,可以提高文件的读写效率。

//读取input.txt文件 1
    public  List<String> readAndPrintFile(String filePath) {
        List<String> input = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                input.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return input;
    }

单元测试

在这里插入图片描述

异常处理

在程序的实现过程中主要通过try-catch方式来实现异常的捕获以及处理。
例如在 readAndPrintFile()函数中,使用try读取input.txt文件的内容,如果catch捕获到异常,则打印出异常堆栈信息,方便定位问题对程序进行修改。在Lib类中的其他方法也有诸多相似的异常处理方式,不再一一列举。

在这里插入图片描述

心得体会

在这次作业中,我从对json只有一点点了解(上学期移动应用开发课程中学习基础的鸿蒙开发时,有使用过鸿蒙的json解析工具,来解析爬取到的网页数据),到通过csdn、github查阅相关资料开始逐步对json有些了解,并学习了如何使用java语言获取json字符串并解析json字符串中的数据,对我的java编程能力提升有很大帮助。于此同时在此次作业中也系统地复习IO流相关知识,让我对生疏了许多的java编程得到了比较充分的复习。
此外让我感悟最深的是博客前面提到的PSP表格,它让我明白了需求分析、设计文档以及测试都是软件开发过程中必不可少的环节。因为没能在分析以及测试阶段做足工作,导致我在编码阶段浪费了大量不必要的时间。在今后软件开发过程中,应该更加注重对项目的前期分析和后期测试,而不能一味盲目地进行具体编码。

...全文
77 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

122

社区成员

发帖
与我相关
我的任务
社区描述
FZU-SE
软件工程 高校
社区管理员
  • LinQF39
  • 助教-吴可仪
  • 一杯时间
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧