软件工程实践第二次作业
这个作业属于哪个课程 | 软件工程实践-2023学年-W班 |
---|---|
这个作业要求在哪里 | 软件工程实践第二次作业——个人实战 |
这个作业的目标 | 复习Java, 熟悉JSON文件的读取, 学习Git在实际开发中的操作 |
其他参考文献 | CSDN 稀土掘金 |
目录
Gitcode项目地址
PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 35 | 60 |
• Estimate | • 估计这个任务需要多少时间 | 1200 | 1500 |
Development | 开发 | 900 | 1200 |
• Analysis | • 需求分析(包括学习新技术) | 60 | 90 |
• Design Spec | • 生成设计文档 | 60 | 90 |
• Design Review | • 设计复审 | 60 | 90 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 60 | 90 |
• Design | • 具体设计 | 120 | 180 |
• Coding | • 具体编码 | 600 | 800 |
• Code Review | • 代码复审 | 120 | 130 |
• Test | • 测试(自我测试,修改代码,提交修改) | 120 | 100 |
Reporting | 报告 | 180 | 120 |
• Test Repor | • 测试报告 | 60 | 50 |
• Size Measurement | • 计算工作量 | 60 | 40 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 40 |
合计 | 1880 | 2080 |
解题思路描述
整体思路
由于所有的指令都存储在输入文件中,因此首要任务是读取这些输入文件,并根据其中的指令执行相应操作。具体操作包括调用不同的方法来处理数据,并将相关的选手信息和比赛结果写入到输出文件中。处理这些信息的核心在于对JSON格式数据的有效解析。
JSON 的读取
我使用了阿里巴巴的fastjson2工具包来进行读取
接口设计和实现过程
创建一个名为Players的类,该类含有一个静态方法playersOutput,该方法负责输出参赛选手的信息。该方法通过利用JSONObject和JSONArray来迭代JSON格式的数据,以提取选手的详细信息。
另外,构建一个名为Result的类,其中包含一个静态方法resultOutput用于输出比赛的结果。此方法同样通过JSONObject和JSONArray来遍历JSON数据,以获取比赛结果的相关信息。
关键代码展示
public class Players {
/**
* 输出选手信息
*
* @param path 输出文件的路径
*/
public static void playersOutput(String path) throws IOException {
Path jsonPath = Paths.get("222100223/src/data/players.json");
//jar包所用路径
//Path jsonPath = Paths.get("src/data/players.json");
String jsonStr = Files.readString(jsonPath, StandardCharsets.UTF_8);
JSONArray jsonArray = JSONArray.parseArray(jsonStr);
File file = new File(path);
FileWriter fileWriter = new FileWriter(file,true);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObject0 = jsonArray.getJSONObject(i);
JSONArray participationsArray = jsonObject0.getJSONArray("Participations");
for (int j = 0; j < participationsArray.size(); j++){
JSONObject jsonObject1 = participationsArray.getJSONObject(j);
String FirstName = jsonObject1.getString("PreferredFirstName");
String LastName = jsonObject1.getString("PreferredLastName");
fileWriter.write("Full Name:" + LastName + " " + FirstName + "\n");
String gender = jsonObject1.getString("Gender").equals("0") ? "Male" : "Female";
fileWriter.write("gender:" + gender + "\n");
String country = jsonObject1.getString("NAT");
fileWriter.write("Country:" + country + "\n");
fileWriter.write("-----\n");
}
}
fileWriter.close();
}
}
public class Results {
/**
* 输出比赛结果
*
* @param path 输出文件的路径
*/
public static void resultsOutput(String path, String event) throws IOException {
File file = new File(path);
FileWriter fileWriter = new FileWriter(file,true);
//synchronised结尾的results包下的json文件代表双人项目
Path jsonpath = Paths.get("222100223/src/data/results/" + event + ".json");
//jar包所用路径
//Path jsonpath = Paths.get("src/data/results/" + event + ".json");
String jsonStr = Files.readString(jsonpath, StandardCharsets.UTF_8);
//层层深入寻找目标元素
JSONObject eventObject = JSONObject.parseObject(jsonStr);
JSONArray HeatsJArr = eventObject.getJSONArray("Heats");
JSONArray resultsJArr = HeatsJArr.getJSONObject(0).getJSONArray("Results");
for(int k = 0; k < resultsJArr.size(); k++)
{
JSONObject resultObj = resultsJArr.getJSONObject(k);
String FullName = resultObj.getString("FullName");
if (FullName.contains("/")) {
JSONArray CompetitorJArr = resultObj.getJSONArray("Competitors");
JSONObject A = CompetitorJArr.getJSONObject(0);
JSONObject B = CompetitorJArr.getJSONObject(1);
String FullNameA = A.getString("FullName");
String FullNameB = B.getString("FullName");
String LastNameA = A.getString("LastName");
String LastNameB = B.getString("LastName");
int compare = LastNameA.compareTo(LastNameB);
if (compare < 0) fileWriter.write("Full Name:" + FullNameA + " & " + FullNameB + "\n");
else fileWriter.write("Full Name:" + FullNameB + " & " + FullNameA + "\n");
}
else fileWriter.write("Full Name:" + FullName + "\n");
String Rank = resultObj.getString("Rank");
String TotalPoints = resultObj.getString("TotalPoints");
fileWriter.write("Rank:" + Rank + "\n");
JSONArray divesJArr = resultsJArr.getJSONObject(0).getJSONArray("Dives");
fileWriter.write("Score:");
//每位选手依次展示五次跳水的分数
for (int i = 0; i < divesJArr.size(); i++)
{
JSONObject divesObj = divesJArr.getJSONObject(i);
String points = divesObj.getString("DivePoints");
//第五轮特殊格式处理
if (i == divesJArr.size() - 1){
fileWriter.write(points);
break;
}
fileWriter.write(points + " + ");
}
fileWriter.write(" = " + TotalPoints + "\n");
fileWriter.write("-----" + "\n");
}
fileWriter.close();
}
}
public class DWASearch {
public static void main(String[] args) throws IOException {
//最终命令行展示
//java -jar DWASearch.jar input.txt output.txt
File file = new File(args[1]);
if (!file.exists()) file.createNewFile();
else {
file.delete();
file.createNewFile();
}
BufferedReader reader = new BufferedReader(new FileReader(args[0]));
//reader = new BufferedReader(new FileReader(in));
String cmd = reader.readLine();
while (cmd != null) {
System.out.println(cmd);
if (cmd.equals("players")) {
Players.playersOutput(args[1]);
} else if (cmd.startsWith("result ")) {
String event = cmd.substring(7);
System.out.println(event);
if (isValidate(event)) Results.resultsOutput(args[1], event);
else {
FileWriter fileWriter0 = new FileWriter(file, true);
fileWriter0.write("N/A" + "\n");
fileWriter0.write("-----" + "\n");
fileWriter0.close();
}
} else {
FileWriter fileWriter1 = new FileWriter(file, true);
fileWriter1.write("Error" + "\n");
fileWriter1.write(("-----" + "\n"));
fileWriter1.close();
}
cmd = reader.readLine();
}
}
public static boolean isValidate(String event)
{
File dir = new File("222100223/src/data/results");
//jar包所用路径
//File dir = new File("src/data/results");
File[] files = dir.listFiles();
event = event + ".json";
if (files != null) {
for (File file:files)
{
if (file.getName().equals(event)) return true;
}
}
return false;
}
性能改进
在Java中,有多种高级的I/O流可以用于读取数据,每种流都有其特定的用途。以下是Java中几种高级I/O流的使用方法:
-
BufferedReader/BufferedWriter:
BufferedReader
和BufferedWriter
提供缓冲的读写功能,可以提高字符流的读写效率。BufferedReader
可以使用readLine()
方法一次读取一行文本。
-
DataInputStream/DataOutputStream:
- 用于读写原始数据类型(如int, float, long, double等)和字符串。
DataInputStream
允许应用程序以便携方式从底层输入流中读取基本Java数据类型。
-
ObjectInputStream/ObjectOutputStream:
- 用于读写对象,实现对象的序列化和反序列化。
- 对象必须实现
Serializable
接口。
-
NIO (New I/O):
- Java的New I/O库,提供了更为高效的I/O操作,是面向缓冲区的,可以通过它更加细粒度地控制数据的读写。
- 包含
ByteBuffer
,CharBuffer
,IntBuffer
等各种缓冲区类,以及FileChannel
等通道类。
-
Files类(Java 7+):
- 提供了一系列的静态方法来更加简洁地读写文件。
- 可以使用
Files.readAllLines()
或Files.newBufferedReader()
读取文件的所有行。 Files
类与Path
类一起使用,提供了更高级的文件操作能力。
下面是一个使用BufferedReader
来读取文件内容的示例:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFileExample {
public static void main(String[] args) {
String filePath = "path/to/your/file.txt";
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
对于更高级或特定用途的文件读取,可以选择合适的流来实现,例如使用FileChannel
来进行更高效的文件I/O操作:
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class NIOFileReadExample {
public static void main(String[] args) {
String filePath = "path/to/your/file.txt";
try (FileChannel fileChannel = (FileChannel)Files.newByteChannel(Paths.get(filePath), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (fileChannel.read(buffer) > 0) {
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
单元测试
覆盖率图
@Test
public void test() throws IOException {
String in = "222100223/src/input.txt";
String out = "222100223/src/output.txt";
File file = new File(in);
try {
if (!file.exists()) file.createNewFile();
else {
file.delete();
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file);
fileWriter.write("player" + "\n");
fileWriter.write("Players" + "\n");
fileWriter.write("resultwomen 1m springboard" + "\n");
fileWriter.write("result women 10m springboard" + "\n");
fileWriter.write("result men 10m platform" + "\n");
fileWriter.write("players" + "\n");
fileWriter.write("result sss" + "\n");
fileWriter.write("result detail" + "\n");
fileWriter.write("result men 10m synchronised" + "\n");
fileWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
DWASearch.main(new String[]{in, out});
}
异常处理
使用try-with-resource 和IOException进行处理
心得体会
本次作业让我真正熟悉了json文件,还有git的各种操作,比如远程仓库删除文件时,在本地仓库合并分支时会遇到本地文件被删除的情况,此时可以用git查看历史记录并且还原分支位置来恢复至之前的状态,再手动解决冲突,就能同步远程和本地仓库,最终顺利推送文件。单元测试使代码的严谨性进一步提高