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

这个作业属于哪个课程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对程序进行单元测试。总的来说,本次实践我收获良多,一次次的代码提交和功能封装让我更清晰的了解了应该如何高效的去完成一个项目并具有一定的可读性。

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值