这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2020 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11167 |
这个作业的目标 | ①读写json文件并统计数据,以命令行展示 ②养成良好的开发习惯 |
学号 | 031802309 |
使用语言 | C++ |
一、PSP 表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
Estimate | 估计这个任务需要多少时间 | 30 | 20 |
Development | 开发 | ||
Analysis | 需求分析 (包括学习新技术) | 60 | 120 |
Design Spec | 生成设计文档 | 20 | 30 |
Design Review | 设计复审 | 40 | 40 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 40 | 30 |
Design | 具体设计 | 40 | 40 |
Coding | 具体编码 | 360 | 520 |
Code Review | 代码复审 | 20 | 40 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 240 |
Reporting | 报告 | ||
Test Report | 测试报告 | 60 | 60 |
Size Measurement | 计算工作量 | 30 | 30 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 90 | 120 |
合计 | 910 | 1290 |
二、解题思路描述
本次作业要求制作一个程序统计和分析 GitHub 的用户行为数据。原始数据以多个 json 对象给出,保存在文件中。我将其命名为 Data.json 。可以分为以下几个部分进行思考:
1.读写 json 文件。确定了 C++ 作为开发语言后,我上网查阅了 C++ 解析 json 的方法,了解到两个库: JsonCpp 和 CJsonObject 。我选择了 JsonCpp 来进行解析。读取原始数据文件,提取所需数据并写入 Temp_Json.json 文件。解析命令行参数,遍历 Temp_Json.json 文件,根据所需参数对数据进行统计。
2.自定义命令行参数。下载 getopt 库,学习 getopt( ) 、getopt_long( ) 等函数的用法。
3.使用Git进行版本控制。
三、设计实现过程
各函数之间的关系如图所示。
四、代码说明
在主函数中设置命令行参数,根据参数解析结果调用不同的函数。
int main(int argc, char** argv) {
int opt;
int digit_optind = 0;
int option_index = 0;
string user, event, repo;
char* optstring = "i:u:e:r:";
static struct option long_options[] =
{
{"init", 1, NULL, 'i'},
{"user", 1, NULL, 'u'},
{"event", 1, NULL, 'e'},
{"repo", 1, NULL, 'r'},
{ 0, 0, 0, 0 }
};
while ((opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != -1) {
switch (opt) {
case 'i':
Init(optarg);
break;
case 'u':
user = optarg;
break;
case 'e':
event = optarg;
break;
case 'r':
repo = optarg;
break;
}
}
if (!user.empty() && !event.empty() && !repo.empty()) {
Num_User_Event_Repo(user, event, repo);
}
if (user.empty() && !event.empty() && !repo.empty()) {
Num_Event_Repo(event, repo);
}
if (!user.empty() && !event.empty() && repo.empty()) {
Num_User_Event(user, event);
}
return 0;
}
初始化函数:Init( );
逐行读取 data.json 文件,提取其中的数据 type 、actor_login 和 repo_name,并将其重新序列化,写入 Temp_Json.json 文件。
void Init(string path) {
//cout << "进入初始化." << endl;
int i;
string str;
Json::Value value;
Json::Value value1;
Json::Reader reader;
Json::StyledWriter sw;
ifstream file(path, ios::binary);
if (!file.is_open()) {
cout << "Data文件打开失败." << endl;
return;
}
i = 0;
ofstream os;
os.open("../Data/Temp_Json.json", std::ios::out | std::ios::app);
if (!os.is_open()) {
cout << "Temp_Json.json文件创建失败." << endl;
return;
}
os << "[" << endl;
while (getline(file, str)) {
i++;
//cout << i << endl;
if (reader.parse(str, value)) {
string type = value["type"].asString();
string actor_login = value["actor"]["login"].asString();
string repo_name = value["repo"]["name"].asString();
value1["id"] = Json::Value(i);
value1["user"] = Json::Value(actor_login);
value1["event"] = Json::Value(type);
value1["repo"] = Json::Value(repo_name);
os << sw.write(value1);
os << "," << endl;
}
else {
cout << "Data文件读取失败." << endl;
return;
}
}
os << "]" << endl;
os.close();
file.close();
//cout << "初始化完成." << endl;
return;
}
查询某用户在某项目的某事件数量 :Num_User_Event_Repo( );
从 Temp_Json.json 中读取 json ,保存在字符串 str 中,对其进行遍历与统计。
void Num_User_Event_Repo(string u, string e, string r) {
//cout << u << "用户在" << r << "项目的" << e << "事件数量为:" << endl;
int ret = 0;
string str, user, event, repo;
Json::Reader reader;
Json::Value value;
ifstream ifile("../Data/Temp_Json.json");
ostringstream buf;
char ch;
while (buf && ifile.get(ch))
buf.put(ch);
str = buf.str();
//cout << str << endl;
reader.parse(str, value);
int size = value.size();
//cout << "size:" << size << endl;
for (int i = 0; i < size; ++i) {
user = value[i]["user"].asString();
event = value[i]["event"].asString();
repo = value[i]["repo"].asString();
//cout << user << " " << event << " " << repo << endl;
if (u == user && e == event && r == repo) {
ret++;
}
}
cout << ret << endl;
return;
}
Num_User_Event( ); 和 Num_Event_Repo( ); 与之同理,故不写出。
五、本地测试
命令行运行结果如下:
为了验证我的程序运行结果,我用编辑器查找了一下。如下图,willdollman 有4次匹配,查到的两个 event 都是 PushEvent 。运行结果正确。
六、代码规范链接
七、困难及总结
VS 编译时报错,显示有无法解析的外部符号,原因是找不到库文件,即 lib 文件。解决方案是用 VS 配置项目属性,在库目录里添加相应库文件所在的目录。
命令行运行时崩溃,并打出错误:JsonCpp Assertion `type_ == nullValue || type_ == objectValue(Jsoncpp 采用 Assert 作为错误处理方法。)原因:读 json 时格式不匹配。我在存数据时是以 [{},{}] 的格式去存的,读的时候应用相匹配的方法去读。解决方案:value后加下标[i]。
遇到的 Bug 和花费的时间都比我预想的要多,不过程序跑起来那一刻还是令人开心的。