1 前言
我们经常在编写软件的时候,需要加载log文件来记录程序运行过程中可能会出现的bug,或者记录一些重要的运行信息。一旦一个目录下生成很多log文件后,实际上我们管理与分析还是需要费一些时间的。这其中就需要我们懂得怎样读取log文件,怎样遍历目录,怎样解析数据等等一系列操作。
下面我们直接通过一个实例来了解各个部分是如何实现的,这个实例的要求如下:
①、D盘log目录下有很多.log文件,我们需要从每个文件中提取数据(隐藏两个任务:打开读取文件;遍历目录);
②、我们需要从文件中提取speed关键字后面对应的数据放入到Excel表格.csv文件中。
2 程序实现
2.1 读取文件
以前从C开始我们就学习了使用fopen()打开文件,fread()读取信息,后来由于存在不安全性,又有了类似的fopen_s()相关定义。但是本次我们使用更上层一些的流操作来读取文件,该类方法定义在#include<fstream>
中,实现如下:
#include<fstream>
using namespace std;
void GetLog(const string& file)
{
//string file = "D:/log/1.log";// 放置log文件的目录
ifstream logFile(file); // 构造一个文件流读取对象
string str;
while (getline(logFile, str)) // 隔行读入数据
{
// ... // 数据处理部分
str.clear(); // 重复加载,所以每次需要清空
}
logFile.close(); // 关闭文件
}
上面的ifstream类是用来构造读取文件对象的类,对应还有构造输出到文件的对象的类ofstream。如果既存在读入和存取,有fstream类,根据自己的需要定义对应的类,然后后面我们就可以像终端上流输入输出一样处理加载的数据。
2.2 遍历日志目录
有了上面的文件读取功能函数,下面我们来看看如何加载一个目录下所有log文件来进行读取与分析。这里主要用到#include<io.h>
头文件中定义的_findfirst()和_findnext()函数接口来依次读取所有文件,以及构造结构体 _finddata_t对象来保存目录下文件基本信息。我们还是直接看程序:
#include<string> // 字符串类
#include<io.h> // 遍历操作
struct _finddata_t fileinfo; // 存储文件信息的结构体对象
string file = "D:/log/"; // 放置log文件的目录
string strFile = file + "*.log";
/***遍历目录系统函数要求先尝试寻找一个文件,看是否存在***/
long handle;
if ((handle = _findfirst(strFile.c_str(), &fileinfo)) == -1L)
{
return 0; // 如果查询log文件失败,直接返回
}
else
{
strFile = file + fileinfo.name;
GetLog(strFile); // 对第一个加载的文件处理
/***一直遍历,直到所有.log文件得到加载与处理***/
while (!(_findnext(handle, &fileinfo)))
{
strFile = file + fileinfo.name;
GetLog(strFile); // 文件处理
}
coutReport.close(); // 释放文件加载
_findclose(handle); // 释放遍历目录的句柄
}
2.3 数据处理
我们的案例中是一个小小的处理要求,就是对log文件下提取一下speed关键字后面记录的数据。这里提取数据并一一对所有字符串处理的操作主要用到定义在#include<sstream>
中字符串流操作的stringstream类。跟fstream中定义的一样,istringstream类是从文件读入数据,而ostringstream类是将数据存入文件,而stringstream类就是两种操作都可以。程序如下:
#include<sstream> // 字符串流操作
#include<string> // 字符串类
#include<io.h> // 遍历操作
using namespace std;// 标准库命名空间
const char* coutFile = "D:/log/output.csv"; // 输出提取数据到csv文件
// 上面隔行读入的数据
while (getline(logFile, str))
{
stringstream strRead(str);
string oneWord;
while (strRead >> oneWord) // 一个个word加载进去
{
if (oneWord.compare("Speed") == 0) // 字符串查询
{
int result;
strRead >> result; // Speed后面的数字输出到result中
cout << result << endl; // 写入文件,并且空行
}
}
str.clear(); // 重复加载,所以每次需要清空
}
3 完整参考程序
#include<iostream> // cin、cout
#include<fstream> // 包含文件读取类与方法
#include<sstream> // 字符串流操作
#include<string> // 字符串类
#include<io.h> // 遍历操作
using namespace std;// 标准库命名空间
string file = "D:/log/"; // 放置log文件的目录
const char* coutFile = "D:/log/output.csv"; // 输出提取数据到csv文件
ofstream coutReport(coutFile); // 构建输出结果文件类对象
void GetInfo(const string& filePath)
{
ifstream logFile(filePath);
string str;
// 隔行读入数据
while (getline(logFile, str))
{
stringstream strRead(str);
string oneWord;
while (strRead >> oneWord) // 一个个word加载进去
{
if (oneWord.compare("Speed") == 0)
{
int result;
strRead >> result; // Speed后面的数字输出到result中
cout << result << endl; // 写入文件,并且空行
}
}
str.clear(); // 重复加载,所以每次需要清空
}
// 关闭文件
logFile.close();
}
int main()
{
struct _finddata_t fileinfo;
string strFile = file + "*.log";
/***遍历目录系统函数要求先尝试寻找一个文件,看是否存在***/
long handle;
if ((handle = _findfirst(strFile.c_str(), &fileinfo)) == -1L)
{
return 0; // 如果查询log文件失败,直接返回
}
else
{
strFile = file + fileinfo.name;
GetInfo(strFile); // 文件处理
/***一直遍历,直到所有.log文件得到加载与处理***/
while (!(_findnext(handle, &fileinfo)))
{
strFile = file + fileinfo.name;
GetInfo(strFile); // 文件处理
}
coutReport.close(); // 释放文件加载
_findclose(handle); // 释放遍历目录的句柄
}
return 0;
}
以上是个人学习记录,由于能力和时间有限,如果有错误望读者纠正,谢谢!
转载请注明出处:http://blog.csdn.net/FX677588/article/details/76473528