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

这个作业属于哪个课程2302软件工程
这个作业要求在哪里软件工程第二次作业
这个作业的目标解析JSON文件并通过命令行进行文件的读写
其他参考文献《构建之法》 JSON Editor Online VS 单元测试

目录:

  1. 仓库地址
  2. psp表格
  3. 解题思路
  4. 模块接口的设计与实现
  5. 关键代码展示
  6. 性能优化
  7. 单元测试
  8. 异常处理
  9. 心得体会

1. 仓库地址

222100323 gitcode仓库

2.psp表格

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

3.解题思路描述

3.1 json数据解析

  对于从网站爬取下来的的json数据,我们需要先了解它的结构,但是有的数据是没有缩进的,不利于阅读,所以借助JSON Editor Online网站来进行JSON数据的缩进,转化成树形结构,便于阅读。

3.2 数据读取分析

  而要在代码中要读取JSON文件,我们还需要借助第三方库,这边使用的nlohmann来帮助解析JSON文件,我们可以将JSON文件视为一个多维数组,根据它的结构来进行数据读取和处理。

4.模块接口的设计与实现

4.1功能封装

  程序主要分为俩个部分:DWASearch.h(头文件)和DWASearch.cpp(程序主体),主要实现了俩个功能:1.读取并输出所有选手信息;2.读取并输出比赛信息;总的来说就是一个读写文件的过程,所以构造了一个output类来负责文件的读写以及读入指令的辨别,并在该类中还有俩个内部类:PlayerHandler类ResultHandler类来分别负责输出选手信息和比赛信息。同时设置结构体PlayerResult用来暂存从文件读出的信息用于排序后输出。

class Output{
public:
 PlayerHandler playerHandler;
 ResultHandler resultHandler;
 void event(ofstream &outputFile,const string &command);
 bool isFirstWordResult(const string &str);
};

  而在俩个内部类中分别设置函数来进行选手/比赛信息的处理,将具体功能封装给各个函数,通过函数的调用来进行文件的读写

   //处理选手信息的类 
class PlayerHandler {
public:
    void printPlayers(ofstream &outputFile);//输出选手信息 
    static bool comparePlayers(const Player& p1, const Player& p2);//比较函数,排序选手 
    static string removeQuotes(const string& str);//去除引号,统一输出格式 
};
// 封装处理比赛结果的类
class ResultHandler {
public:
    void result(ofstream &outputFile, const string &eventName);//输出决赛信息 
    void resultDetail(ofstream& outputFile,const string str);//输出比赛详细信息 
    static void doublename(string& str);//处理有俩个运动员的情况 
    static string fillscore(Result& result,const json& player);//计算选手得分 
    static void threeDetail(json& data,vector<Result>& results);//处理有三次比赛的情况 
    static void twoDetail(json& data,vector<Result>& results);//处理有俩次比赛的情况 
    static void oneDetail(json& data,vector<Result>& results);//处理只有一次比赛的情况 
    static bool compareResults(const Result& a, const Result& b);//比较函数,排序比赛信息 
};
4.2实现过程

在这里插入图片描述

5关键代码展示

5.1输出选手信息
//输出选手信息 
void PlayerHandler::printPlayers(ofstream& outputFile) {
	// Json读取
    ifstream ifs("datas/athletes.json");
    if (!ifs.is_open()){
    	cerr << "Error opening file! " << '\n';
    	return; 
	}        
    json data = json::parse(ifs);
    // 存储选手信息的容器
    vector<Player> players;
    for (const auto& participant : data) {
        Player player;
        for(const auto& contestants : participant["Participations"]){
        	player.fullName = removeQuotes(contestants["PreferredLastName"]) + " " + removeQuotes(contestants["PreferredFirstName"]);
        	player.gender = (contestants["Gender"] == 0 ? "Male" : "Female");
        	player.country = removeQuotes(contestants["NAT"]);
        	players.push_back(player);
		}
    }
    // 对选手进行排序
    stable_sort(players.begin(), players.end(), comparePlayers);
    // 输出排序后的选手信息
    for (const auto& player : players) {
        outputFile << "Full Name:" << player.fullName << "\n";
        outputFile << "Gender:" << player.gender << "\n";
        outputFile << "Country:" << player.country << "\n";
        outputFile << "-----" << "\n";
    }
    return ;
}
5.2输出决赛结果
//输出比赛的决赛结果 
void ResultHandler::result (ofstream& outputFile,const string &str){
	// Json读取
    ifstream ifs(str);
    if (!ifs.is_open()){
    	cerr << "Error opening file! " << '\n';
    	return; 
	}        
    json data = json::parse(ifs);
    // 获取比赛的决赛结果
    json finalResults = data["Heats"][0]["Results"];
    // 写入 output.txt 文件
    for (const auto& result : finalResults) {
        if (!result["FullName"].is_null() && !result["Rank"].is_null() && !result["TotalPoints"].is_null() && !result["Dives"].is_null()) {
			string fullName = result["FullName"].get<string>();
			doublename(fullName);	
            string rank = to_string(result["Rank"].get<int>()); // 将数字类型转换为字符串类型
            string totalScore = result["TotalPoints"].get<string>();
			string scoreStr;
            for (const auto& dive : result["Dives"]) {
                if (!dive["DivePoints"].is_null()) {
                    scoreStr += dive["DivePoints"].get<string>() + " + "; 
                    }
                }
            scoreStr = scoreStr.substr(0, scoreStr.size() - 3) + " = " + totalScore;
            outputFile << "Full Name:" << fullName << '\n';
            outputFile << "Rank:" << rank << '\n';
            outputFile << "Score:" << scoreStr << '\n';
            outputFile << "-----" << '\n';
        	}
        }
    return ;
}
5.3输出详细结果
//输出比赛详细结果 
void ResultHandler::resultDetail(ofstream& outputFile,const string& str){
	ifstream ifs(str);
	if (!ifs.is_open()){
    	cerr << "Error opening file! " << '\n';
    	return; 
	}        
    json data = json::parse(ifs);
    vector<Result> results;
    // 根据比赛场次选择不同函数处理数据 
    int num=data["Heats"].size();
    if(num==3)
    	threeDetail(data,results);
    if(num==2)
    	twoDetail(data,results);
	if(num==1)
    	oneDetail(data,results);
    // 对结果按照排名排序
    sort(results.begin(), results.end(), compareResults);
    //将比赛结果输出到文件中 
    for (const auto& result : results) {
        outputFile << "Full Name:" << result.fullName << "\n";
        outputFile << "Rank:" << result.rank << "\n";
        outputFile << "Preliminary Score:" << result.preliminaryScore << "\n";
        outputFile << "Semifinal Score:" << result.semifinalScore << "\n";
        outputFile << "Final Score:" << result.finalScore << "\n";
        outputFile << "-----\n";
    }
}

6性能优化

1.使用引用传递参数:在函数参数传递过程中,使用引用传递可以避免不必要的拷贝
2.结果缓存:对于多次连续输入重复指令,程序对结果进行缓存,当输入连续指令时不必再次读取数据,而直接输出缓存数据,大大减少运行时间
优化前的运行时间:
在这里插入图片描述

优化后的运行时间:在这里插入图片描述

7.单元测试

使用vs进行单元测试:
在这里插入图片描述

覆盖率:
在这里插入图片描述

8.异常处理

1.命令行异常处理:对于错误的命令行指令,反馈错误并退出程序

if(argc!=3){
		cerr << "Error command." << '\n';
		return 1;
	} 

2.文件打开错误,每次打开相关文件都会有异常处理,当未能正确打开相关文件,反馈错误并退出程序

ifstream inputFile(argv[1]);
    ofstream outputFile(argv[2], ios_base::app);
    if (!inputFile.is_open() || !outputFile.is_open()) {
        cerr << "Error opening files." << '\n';
        return 1;
    }

9.心得体会

  经过本次实践,了解并熟悉了c++如何解析并处理JSON数据以及通过命令行来进行文件的读写。同时学会了如何使用VS对程序进行单元测试。总的来说,本次实践我收获良多,一次次的代码提交和功能封装让我更清晰的了解了应该如何高效的去完成一个项目并具有一定的可读性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值