122
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | <2302软件工程社区> |
|---|---|
| 这个作业要求在哪里 | <软件工程第二次作业——文件读取> |
| 这个作业的目标 | <完成对世界游泳锦标赛跳水项目相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序> |
| 其他参考文献 | 《码出高效_阿里巴巴java开发手册》、 单元测试和回归测试、 工程师的能力评估和发展 |
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 60 | 60 |
| • Estimate | • 估计这个任务需要多少时间 | 60 | 60 |
| Development | 开发 | 1860 | 2190 |
| • Analysis | • 需求分析(包括学习新技术) | 210 | 240 |
| • Design Spec | • 生成设计文档 | 60 | 60 |
| • Design Review | • 设计复审 | 30 | 30 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
| • Design | • 具体设计 | 90 | 120 |
| • Coding | • 具体编码 | 1200 | 1500 |
| • Code Review | • 代码复审 | 120 | 90 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 120 | 120 |
| Reporting | 报告 | 150 | 210 |
| • Test Repor | • 测试报告 | 60 | 120 |
| • Size Measurement | • 计算工作量 | 30 | 30 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 60 |
| 合计 | 2070 | 2460 |
助教提供了从游泳比赛官网上爬取完成的比赛信息(json形式),主要任务分为两步:1.解析json字符串获取所需要的信息 2.完成各个查询功能的实现
以前对JSON没有具体学习过,所以对于JSON文件的格式以及解析方法没有知识积累,查资料获知Java中解析JSON数据通常使用第三方库,比较常用的有Jackson、Gson和Org.json等,在此采用Org.json
带着功能需求阅读助教提供的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类中,方便主程序直接通过函数接口进行调用以及进行单元测试。
readAndPrintFile()用于读取input.txt文件中的所有数据
getResult()函数用于识别input.txt文件中的指令类型以及错误的输入格式,输入正确则返回正确的指令,输入不正确则调用getError()传输相应的错误("N/A" 或 "error")信息到outputToFile()打印到output.txt文件
outputToFile()用于根据命令不同输出所需数据到output.txt
getPlayers()用于读取athletes.json文件中的所有运动员数据,并存储到class Athlete(运动员类)中去,然后输出所有运动员信息到output.txt。在运行过程中会调用getJsonObject()函数获取json对象,并用.getString将所需属性据转换成相应String字符串。
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表格,它让我明白了需求分析、设计文档以及测试都是软件开发过程中必不可少的环节。因为没能在分析以及测试阶段做足工作,导致我在编码阶段浪费了大量不必要的时间。在今后软件开发过程中,应该更加注重对项目的前期分析和后期测试,而不能一味盲目地进行具体编码。