122
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | 2302软件工程 |
|---|---|
| 这个作业要求在哪里 | 软件工程第二次作业--文件读取 |
| 这个作业的目标 | 命令行控制输出2024世界游泳锦标赛跳水项目的选手信息和比赛结果 |
| 其他参考文献 | Json详解及fastjson教程、IDEA单元测试 |
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | 30 |
| • Estimate | • 估计这个任务需要多少时间 | 30 | 30 |
| Development | 开发 | 1240 | 1390 |
| • Analysis | • 需求分析 (包括学习新技术) | 350 | 360 |
| • Design Spec | • 生成设计文档 | 30 | 30 |
| • Design Review | • 设计复审 | 60 | 55 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
| • Design | • 具体设计 | 60 | 75 |
| • Coding | • 具体编码 | 500 | 500 |
| • Code Review | • 代码复审 | 40 | 60 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 180 | 280 |
| Reporting | 报告 | 90 | 105 |
| • Test Repor | • 测试报告 | 40 | 60 |
| • Size Measurement | • 计算工作量 | 20 | 25 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 20 |
| 合计 | 1360 | 1525 |






Lib:
DWASearch:
HashMap<String, String> maps,里面存有之前解析过的有效指令与其对应的比赛信息。 main()函数识别“players”指令后,先查看缓存中是否有现成数据,若有则输出,若无则调用Lib的outputAthletesInfo()获取相应内容。getJsonInfo()获取JSON文件内容,然后利用fastjson2的JSONArray和JSONObject解析数据,最后返回运动员信息。经DWASearch的main()写入到输出文件。
outputEventsResult()getResultId()通过比赛名获取对应的文件ID,调用getJsonInfo()获取文件内容,层层解析,获得比赛结果,返回给DWASearch的main(),最后写入到输出文件。
分析、处理指令
StringBuilder info = new StringBuilder();//存储输出内容
//处理合集中的单条指令
for (int i = 0; i < commands.size(); i++) {
//若有缓存,则取出对应内容
if (maps.containsKey(commands.get(i))) {
info.append(maps.get(commands.get(i)));
//每读1000条写入一次
if ((i + 1) % 1000 == 0) {
BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile, true));
bw.write(info.toString());
bw.close();
info.setLength(0);
}
continue;
}
if (commands.get(i).equals("players")) {//输出所有选手信息
//缓存指令和对应的输出内容
maps.put("players", Lib.outputAthletesInfo());
info.append(Lib.outputAthletesInfo());
} else if (commands.get(i).indexOf(" ") != -1) {
String firstStr = commands.get(i).substring(0, commands.get(i).indexOf(" "));
if (!firstStr.equals("result")) {//无法识别的指令
info.append("Error\n-----\n");
} else {
String eventName = commands.get(i).substring(commands.get(i).indexOf(" ") + 1);
if (list.contains(eventName)) {//输出比赛结果
//缓存指令和对应的输出内容
maps.put(commands.get(i), Lib.outputEventsResult(eventName));
info.append(Lib.outputEventsResult(eventName));
} else {//比赛项目名称不正确
info.append("N/A\n-----\n");
}
}
} else {//无法识别的命令
info.append("Error\n-----\n");
}
//每读1000条写入一次
if ((i + 1) % 1000 == 0) {
BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile, true));
bw.write(info.toString());
bw.close();
info.setLength(0);
}
}
//写入剩余内容
BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile, true));
bw.write(info.toString());
bw.close();
info.setLength(0);
获取运动员信息
//输出所有选手信息
public static String outputAthletesInfo() throws IOException {
//存储待输出的选手信息
StringBuilder athletesInfo = new StringBuilder();
JSONArray jsonArray = JSONArray.parseArray(getJsonInfo(ATHLETES_FILE));
for (int i = 0; i < jsonArray.size(); i++) {
//获取一个国家所有运动员的信息
JSONObject jsonObject = jsonArray.getJSONObject(i);
//获取国名
String countryName = jsonObject.getString("CountryName");
JSONArray athleteList = jsonObject.getJSONArray("Participations");
for (int j = 0; j < athleteList.size(); j++) {
//获取该国家中一位运动员的信息
JSONObject athlete = athleteList.getJSONObject(j);
athletesInfo.append("Full Name:" + athlete.getString("PreferredLastName") + " " + athlete.getString(
"PreferredFirstName") + "\n");
athletesInfo.append("Gender:" + ("0".equals(athlete.getString("Gender")) ? "Male" : "Female") + "\n");
athletesInfo.append("Country:" + countryName + "\n" + "-----" + "\n");
}
}
return athletesInfo.toString();
}
获取比赛结果
//输出决赛每个运动项目结果
public static String outputEventsResult(String sportName) throws IOException {
//存储待输出的比赛结果
StringBuilder eventsResult = new StringBuilder();
//获取比赛结果的文件id
String fileID = getResultId(sportName);
if (fileID != "") {
String file = "src\\data\\results\\" + fileID + ".json";
JSONObject jsonObject = JSONObject.parseObject(getJsonInfo(file));
JSONArray jsonArray = jsonObject.getJSONArray("Heats");
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject everyScore = jsonArray.getJSONObject(i);
if ("Final".equals(everyScore.getString("Name"))) {
//获取该项目的比赛结果
JSONArray results = everyScore.getJSONArray("Results");
for (int j = 0; j < results.size(); j++) {
JSONObject player = results.getJSONObject(j);
//该选手的全名(双人项目,输出名字时用“&”连接,按照选手名(Last Name)从小到大排序)
String fullName = player.getString("FullName");
if (fullName.contains(" / ")) {
String[] str = fullName.split(" / ");
List<String> doubleName = new ArrayList<>();
doubleName.add(str[0]);
doubleName.add(str[1]);
Collections.sort(doubleName);
fullName = doubleName.get(0) + " & " + doubleName.get(1);
}
eventsResult.append("Full Name:" + fullName + "\n");
//该选手的排名
eventsResult.append("Rank:" + player.getString("Rank") + "\n");
//该选手的具体成绩
eventsResult.append("Score:");
JSONArray scores = player.getJSONArray("Dives");
for (int k = 0; k < scores.size(); k++) {
JSONObject diveScore = scores.getJSONObject(k);
//获取每小节的成绩
eventsResult.append(diveScore.getString("DivePoints"));
int len = scores.size();
if (k < len - 1) {
eventsResult.append(" + ");
} else {
//获取总成绩
eventsResult.append(" = " + diveScore.getString("TotalPoints") + "\n");
}
}
eventsResult.append("-----" + "\n");
}
return eventsResult.toString();
}
}
}
return "";
}
通过比赛项目名获得比赛结果文件的id
//通过比赛项目名获得比赛结果文件的id
private static String getResultId(String sportName) throws IOException {
JSONObject jsonObject = JSONObject.parseObject(getJsonInfo(EVENTS_FILE));
JSONArray jsonArray = jsonObject.getJSONArray("Sports");
JSONObject sports = jsonArray.getJSONObject(0);
JSONArray diving = sports.getJSONArray("DisciplineList");
for (int i = 0; i < diving.size(); i++) {
//获得该跳水项目的数据
JSONObject divingSport = diving.getJSONObject(i);
//获取该项目的项目名
String str = divingSport.getString("DisciplineName").toLowerCase();
//获取文件id
if (str.equals(sportName)) {
return divingSport.getString("Id");
}
}
return "";
}
获取json文件的内容
//获取json文件的内容
private static String getJsonInfo(String path) throws IOException {
StringBuilder sb = new StringBuilder();
File file = new File(path);
if (file.exists()) {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
fr.close();
return sb.toString();
} else {
throw new FileNotFoundException("找不到文件" + path);
}
}
HashMap<String, String> maps = new HashMap<>();//缓存命令和对应的输出内容
处理指令时,优先查看缓存是否有现成数据
if (maps.containsKey(commands.get(i))) {
info.append(maps.get(commands.get(i)));
continue;
}
处理首次出现的指令时,记得更新缓存数据
maps.put("players", Lib.outputAthletesInfo());
用10w条result women 10m platform指令测试,可以看到,引入缓存后,运行速度明显加快
优化前:


使用Junit进行单元测试,教程:IDEA单元测试
测试代码:


代码:



在完成作业的过程中,我认识到软件开发的整体流程,过去只想着代码如何跑通,但这次的作业不仅仅要跑通代码,还要考虑代码的可读性、复用率和性能等。从构思、规划到代码实现、性能测试,再到编写总结报告,完整的一套流程让我收获颇丰,我学会了如何用git管理项目文件,在IDEA进行单元测试,如何优化代码性能,对软件开发的意义有了更深的感悟。