#include <iostream>
#include <fstream>    //包含文件操作的头文件 
#include <cstring>    //字符串操作头文件 
using namespace std;

//added in 3.0, 时间类型的结构定义
struct Time_t
{
	int year, month, day;
	int hour, minute, second;
};

//added in 3.0, 计算时长的函数声明
int TimeDifference(Time_t, Time_t); 

int main()
{
	//ifstream fin("log.txt");  //ifstream表示input file stream
	//上面这一行也可以写成如下两行:
	ifstream fin;
	fin.open("log.txt"); 
	int user_count = 0;  
	char ids[600][20];  //记录所有的编号 
	bool online[600];   //added in 3.0, 记录在线状态
	Time_t last_on[600];  //added in 3.0, 记录上次登录时间
	int secs[600];     //added in 3.0, 累计在线秒数 
	while(!fin.eof())     //eof表示end of file
	{
		Time_t t;
		char tmp, id[20], operation[10];
		
		//added in 3.0, 获取文本文件中的一行(结构体版本) 
		fin >> t.year >> tmp >> t.month >> tmp >> t.day;    // 2015/4/21
		fin >> t.hour >> tmp >> t.minute >> tmp >> t.second;  // 11:16:16
		fin >> id;    // 40dbae14f777cdd
		fin >> operation;   // LOGIN
		
		int found = -1;
		
		//判断是否是新用户 
		for(int i = 0; i < user_count; i++)
			if(strcmp(id, ids[i]) == 0)
			{
				found = i;
				break;
			}
			
		//如果是新用户,记录新用户的登录状态,并记录上次登录时间 
		if(found == -1)  //debug记录:千万不要写掉了一个等号 
		{
			strcpy(ids[user_count], id);  
			//added in 3.0, 记录新用户的登录状态 
			if(strcmp(operation, "LOGIN") == 0)
			{
				online[user_count] = true;  //登录状态改为“在线” 
				last_on[user_count] = t;  //记录上次登录时间
				//特别注意:这里t为结构类型,它与普通类型一样,也是能赋值给一个数组元素的! 
			}
			else
				online[user_count] = false;
			user_count++;
		}
		//如果不是新用户,修改登录状态,记录在线时长 
		else
		{
			if(strcmp(operation, "LOGIN") == 0)  //如果当前操作是登录操作 
			{
				if(!online[found])  //而且当前的状态是不在线 
				{
					online[found] = true;  //就把当前状态改为在线 
					last_on[found] = t;   //并把登录时间记下来 
				}
			}
			else  //否则就是登出操作
			{
				if(online[found])  //并且当前状态是在线 
				{
					online[found] = false;  //就把当前状态改为不在线 
					
					//并调用函数,计算两个时刻之差
					secs[found] += TimeDifference(last_on[found], t); 
				}
			} 
		}
	} 
	fin.close();  //关闭文件
	
	//added in 3.0, 输出每一个用户的在线时长
	for(int i = 0; i < user_count; i++) 
		cout << ids[i] << " " << secs[i] << endl;  
	return 0; 
}

//added in 3.0, 计算时间差,已知只会出现2015年内的时间
//若要计算位于不同年的时刻之间的时间差,则还需考虑int型数据的最大容量,防止溢出 
int TimeDifference(Time_t s, Time_t t) 
{
	int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int day_count = t.day - s.day;
	for(int i = s.month; i < t.month; i++)
		day_count += days[i - 1];  //减1的目的是数组下标与实际的月份数相一致 
	
	int result = day_count * 60 * 60 * 24;
	result += (t.hour - s.hour) * 60 * 60;
	result += (t.minute - s.minute) * 60;
	result += (t.second - s.second);
	return result;
}

运行结果:

累计在线时长 hive_Time

可以估计出,整个控制台缓冲区并没有500多行,有一些靠前面的输出结果被掐掉了。为解决这个问题,可以把输出结果输出到另一个文件中。

#include <iostream>
#include <fstream>    //包含文件操作的头文件 
#include <cstring>    //字符串操作头文件 
using namespace std;

//added in 3.0, 时间类型的结构定义
struct Time_t
{
	int year, month, day;
	int hour, minute, second;
};

//added in 3.0, 计算时长的函数声明
int TimeDifference(Time_t, Time_t); 

int main()
{
	//ifstream fin("log.txt");  //ifstream表示input file stream
	//上面这一行也可以写成如下两行:
	ifstream fin;
	fin.open("log.txt"); 
	int user_count = 0;  
	char ids[600][20];  //记录所有的编号 
	bool online[600];   //added in 3.0, 记录在线状态
	Time_t last_on[600];  //added in 3.0, 记录上次登录时间
	int secs[600];     //added in 3.0, 累计在线秒数 
	while(!fin.eof())     //eof表示end of file
	{
		Time_t t;
		char tmp, id[20], operation[10];
		
		//added in 3.0, 获取文本文件中的一行(结构体版本) 
		fin >> t.year >> tmp >> t.month >> tmp >> t.day;    // 2015/4/21
		fin >> t.hour >> tmp >> t.minute >> tmp >> t.second;  // 11:16:16
		fin >> id;    // 40dbae14f777cdd
		fin >> operation;   // LOGIN
		
		int found = -1;
		
		//判断是否是新用户 
		for(int i = 0; i < user_count; i++)
			if(strcmp(id, ids[i]) == 0)
			{
				found = i;
				break;
			}
			
		//如果是新用户,记录新用户的登录状态,并记录上次登录时间 
		if(found == -1)  //debug记录:千万不要写掉了一个等号 
		{
			strcpy(ids[user_count], id);  
			//added in 3.0, 记录新用户的登录状态 
			if(strcmp(operation, "LOGIN") == 0)
			{
				online[user_count] = true;  //登录状态改为“在线” 
				last_on[user_count] = t;  //记录上次登录时间
				//特别注意:这里t为结构类型,它与普通类型一样,也是能赋值给一个数组元素的! 
			}
			else
				online[user_count] = false;
			user_count++;
		}
		//如果不是新用户,修改登录状态,记录在线时长 
		else
		{
			if(strcmp(operation, "LOGIN") == 0)  //如果当前操作是登录操作 
			{
				if(!online[found])  //而且当前的状态是不在线 
				{
					online[found] = true;  //就把当前状态改为在线 
					last_on[found] = t;   //并把登录时间记下来 
				}
			}
			else  //否则就是登出操作
			{
				if(online[found])  //并且当前状态是在线 
				{
					online[found] = false;  //就把当前状态改为不在线 
					
					//并调用函数,计算两个时刻之差
					secs[found] += TimeDifference(last_on[found], t); 
				}
			} 
		}
	} 
	fin.close();  //关闭文件
	
	//added in 3.1, 把每一个用户的在线时长输出到文件
	ofstream fout;
	fout.open("times.txt"); 
	for(int i = 0; i < user_count; i++) 
		fout << ids[i] << " " << secs[i] << endl;  
	fout.close();
	return 0; 
}

//added in 3.0, 计算时间差,已知只会出现2015年内的时间
//若要计算位于不同年的时刻之间的时间差,则还需考虑int型数据的最大容量,防止溢出 
int TimeDifference(Time_t s, Time_t t) 
{
	int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int day_count = t.day - s.day;
	for(int i = s.month; i < t.month; i++)
		day_count += days[i - 1];  //减1的目的是数组下标与实际的月份数相一致 
	
	int result = day_count * 60 * 60 * 24;
	result += (t.hour - s.hour) * 60 * 60;
	result += (t.minute - s.minute) * 60;
	result += (t.second - s.second);
	return result;
}

累计在线时长 hive_i++_02

可见控制台窗口已经没有输出了,输出到了exe文件根目录下的文本文件中。

累计在线时长 hive_i++_03


写入文件的核心代码是这几行:

//added in 3.1, 把每一个用户的在线时长输出到文件
	ofstream fout;
	fout.open("times.txt"); 
	for(int i = 0; i < user_count; i++) 
		fout << ids[i] << " " << secs[i] << endl;  
	fout.close();

经测试,文件名不能命名为带路径名的形式,否则无法输出。不过,也许需要包含某个头文件也未可知,以后学到再说吧。