2020第一次软工编程作业
这个作业属于哪个课程 | 软件工程 |
---|---|
这个作业要求在哪里 | 第一次编程作业要求 |
这个作业的目标 | 进一步熟悉github,对json文件进行解析并查找 |
学号 | 031802443 |
一、psp表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
Estimate | 估计这个任务需要多少时间 | 770 | 980 |
Development | 开发 | 120 | 150 |
Analysis | 需求分析 (包括学习新技术) | 200 | 300 |
Design Spec | 生成设计文档 | 60 | 75 |
Design Review | 设计复审 | 20 | 20 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
Design | 具体设计 | 40 | 45 |
Coding | 具体编码 | 160 | 180 |
Code Review | 代码复审 | 60 | 100 |
Test | 测试(自我测试,修改代码,提交修改) | ||
Reporting | 报告 | 20 | 20 |
Test Report | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 20 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | ||
合计 | 770 | 980 |
二、解题思路
思路分析
刚看到题目完全不知道在说什么,只好对照示例代码理解题目,通过样例理解了题意,决定使用c++做作业,人菜却要交作业,那只好模仿样例不做优化的解决了,
虽然可能会出现内存溢出,超时,解析错误等等问题,但至少先让程序跑起来
代码组织思维导图
题目主要可以分为五部分
- 命令行参数解析
以前写的代码完全没有用过命令行参数,所以不是很了解,通过搜索引擎查询,学习了用getopt方法处理命令行参数 - json 文件的读取
调用第三方的cJSON库来解析json文件 - 数据统计
利用map统计,将用户名与项目名和事件对应,并记录次数 - 统计数据的存储
将统计出的数据转换为json形式分别存储在三份文件中,分别对应三种不同的查询方式。 - 统计数据的查询
根据命令行参数决定查询文件,并利用cjson解析存储的json文件,得到事件次数
三、学习与设计过程
1.git使用
首先关注助教的b站账号,学习github的使用并一键三连 点这里学习git使用
2.命令行参数的知识
利用getopt_long来解析命令行参数 (https://www.cnblogs.com/hnrainll/archive/2011/09/15/2176933.html),但我用的win下的vs2019,编译时找不到对应的头文件,上网查询之后在git上找到了xgetopt库,和getopt用法相同,只要把文件放进项目里即可使用xgetopt
3.数据读取
利用_findfirst与_findnext遍历所有json文件,并将它们打开读取数据
4.数据存储与查询
将map键值对写入文件中,查询时打开对应json文件并解析即可
四、代码说明
由于我是菜鸡,所以代码只是勉强写完了而且能运行,速度应该很慢
对于命令行参数的读取
string actor_login;
string repo_name;
string event_type;
int opt;
int longindex;
char stri[] = "i::u::r::e::";//短参数的值
char* str = stri;
int type = 0;//根据type来决定查询类型
static struct xoption long_options[] =
{
{"user", xrequired_argument,NULL, 'u'},
{"repo", xrequired_argument,NULL, 'r'},
{"event", xrequired_argument,NULL,'e'},
{"init", xrequired_argument,NULL,'i'},
};//长参数的值
while ((opt = xgetopt_long(argc, argv, str, long_options, &longindex)) != -1)//通过while循环不停地读取参数
{
if (opt == 'i')
{
initFile(argv);//初始化数据
return 0;
}
else if (opt == 'u')
{
type += 1;
actor_login = xoptarg;
}
else if (opt == 'r')
{
type += 2;
repo_name = xoptarg;
}
else if (opt == 'e')
{
event_type = xoptarg;
}
}
初始化方法
unordered_map<string, int> map_user_event;
unordered_map<string, int> map_repo_event;
unordered_map<string, int> map_user_repo_event;
struct _finddata_t fileinfo;
string work_path = get_work_path();//得到当前工作路径
string in_path = work_path + "\\" + argv[2];//得到数据存放路径
string curr = in_path + "\\*.json";//指定json后缀文件
intptr_t handle;
if ((handle = _findfirst(curr.c_str(), &fileinfo)) == -1)
{
return;
}
else
{
ofstream ofile;
GetLineAndSave(in_path, work_path, fileinfo.name,
map_user_event, map_repo_event, map_user_repo_event);
//读取并解析json文件,用引用的方式传map,可以在多次调用中使用同一份unordered_map
while (!(_findnext(handle, &fileinfo)))//如果还有数据文件,继续之前的操作
{
GetLineAndSave(in_path, work_path, fileinfo.name,
map_user_event, map_repo_event, map_user_repo_event);
}
ofstr out_file(work_path);//建立输出类
out_file.write_data(map_user_event, map_repo_event, map_user_repo_event);//调用输出类将解析并处理好的json文件保存到工作目录下,查询时调用这些文件即可
_findclose(handle);
}
查询函数
int search(int type, string actor_login, string repo_name, string event_type)
{
int count = 0;
string work_path = get_work_path();
string in_name;
string search_object;
//根据type不同,改变查找的文件与对应json的key
if (type == 1)
{
in_name = work_path + "\\1.json";
search_object = actor_login + event_type;
}
else if (type == 2)
{
in_name = work_path + "\\2.json";
search_object = repo_name + event_type;
}
else if (type == 3)
{
in_name = work_path + "\\3.json";
search_object = repo_name + event_type + actor_login;
}
else
{
return 0;
}
//开始读取文件
ifstream fin(in_name);
if (!fin)
{
cerr << "请检查是否初始化且初始化成功" << endl;
exit(-1);
}
//读取文件
fin.seekg(0, fin.end);
int length = fin.tellg();
fin.seekg(0, fin.beg);
char* temp = new char[length];
fin.read(temp, length);
//解析生成的cjson文件
cJSON* cJson_test = cJSON_Parse(temp);
if (cJson_test == NULL)
{
cerr << "parse fail" << endl;
exit(-1);
}
else
{
//得到所查询的事件次数
cJSON* cJson_type = cJSON_GetObjectItem(cJson_test, search_object.data());
if (cJson_type != NULL)
{
count = cJson_type->valueint;
}
}
cJSON_Delete(cJson_test);
fin.close();
delete temp;
return count;
}
五、遇到的困难
由于我比较菜,对我而言是相当曲折和艰难的一次作业,很多知识都是临时学习并应用的,理解困难,因此整个程序也没有优化,仅仅是最简单的读取、存储、查找json文件,
速度比较慢,整个程序也比较臃肿,很多地方都是面向过程来进行设计,希望在以后的迭代中能够重构,并对算法进行优化,多看同学的博客,利用多线程来进行优化
六、代码规范
https://github.com/huipai/huipai/blob/master/codestyle.txt
七、总结
在这次实践中学到了很多东西,同时也了解了一部分github的使用,虽然仍旧不怎么熟练,但至少有了不小的进步