3)生成测试数据,模拟观测数据
- 建立结构体存放全国气象站点分钟观测数据
// 存放全国气象站点参数的容器。
vector<struct st_stcode> vstcode;
// 把站点参数文件中加载到vstcode容器中。
bool LoadSTCode(const char *inifile);
// 全国气象站点分钟观测数据结构
struct st_surfdata
{
char obtid[11]; // 站点代码。
char ddatetime[21]; // 数据时间:格式yyyymmddhh24miss
int t; // 气温:单位,0.1摄氏度。
int p; // 气压:0.1百帕。
int u; // 相对湿度,0-100之间的值。
int wd; // 风向,0-360之间的值。
int wf; // 风速:单位0.1m/s
int r; // 降雨量:0.1mm。
int vis; // 能见度:0.1米。
};
- CrtsurfData()函数用于模拟生成全国气象站点分钟观测数据,存放在vsurfdata容器中
// 模拟生成全国气象站点分钟观测数据,存放在vsurfdata容器中。
void CrtSurfData()
{
// 播随机数种子。
srand(time(0));
// 获取当前时间,当作观测时间。
char strddatetime[21];
memset(strddatetime,0,sizeof(strddatetime));
LocalTime(strddatetime,"yyyymmddhh24miss");
struct st_surfdata stsurfdata;
// 遍历气象站点参数的vstcode容器。
for (int ii=0;ii<vstcode.size();ii++)
{
memset(&stsurfdata,0,sizeof(struct st_surfdata));
// 用随机数填充分钟观测数据的结构体。
strncpy(stsurfdata.obtid,vstcode[ii].obtid,10); // 站点代码。
strncpy(stsurfdata.ddatetime,strddatetime,14); // 数据时间:格式yyyymmddhh24miss
stsurfdata.t=rand()%351; // 气温:单位,0.1摄氏度
stsurfdata.p=rand()%265+10000; // 气压:0.1百帕
stsurfdata.u=rand()%100+1; // 相对湿度,0-100之间的值。
stsurfdata.wd=rand()%360; // 风向,0-360之间的值。
stsurfdata.wf=rand()%150; // 风速:单位0.1m/s
stsurfdata.r=rand()%16; // 降雨量:0.1mm
stsurfdata.vis=rand()%5001+100000; // 能见度:0.1米
// 把观测数据的结构体放入vsurfdata容器。
vsurfdata.push_back(stsurfdata);
}
}
- gdb调试新增功能
在末尾设置断点
查看vsurfdata容器内容
4)生成.csv/.xml/.json文件
添加CrtSurfFile函数用于把容器vsurfdata中的全国气象站点分钟观测数据写入文件。
bool CrtSurfFile(const char *outpath,const char *datafmt)// 把容器vsurfdata中的全国气象站点分钟观测数据写入文件。
{
CFile File;
char strFileName[301];// 拼接生成数据的文件名,例如:/tmp/idc/surfdata/SURF_ZH_20210629092200_2254.csv
sprintf(strFileName,"%s/SURF_ZH_%s_%d.%s",outpath,strddatetime,getpid(),datafmt);
if (File.OpenForRename(strFileName,"w")==false)// 打开文件。
{
logfile.Write("File.OpenForRename(%s) failed.\n",strFileName); return false;
}
if (strcmp(datafmt,"csv")==0) File.Fprintf("站点代码,数据时间,气温,气压,相对湿度,风向,风速,降雨量,能见度\n");// 写入第一行标题。
for (int ii=0;ii<vsurfdata.size();ii++)// 遍历存放观测数据的vsurfdata容器。
{
if (strcmp(datafmt,"csv")==0)// 写入一条记录。
File.Fprintf("%s,%s,%.1f,%.1f,%d,%d,%.1f,%.1f,%.1f\n",\
vsurfdata[ii].obtid,vsurfdata[ii].ddatetime,vsurfdata[ii].t/10.0,vsurfdata[ii].p/10.0,\
vsurfdata[ii].u,vsurfdata[ii].wd,vsurfdata[ii].wf/10.0,vsurfdata[ii].r/10.0,vsurfdata[ii].vis/10.0);
}
File.CloseAndRename(); // 关闭文件。
logfile.Write("生成数据文件%s成功,数据时间%s,记录数%d。\n",strFileName,strddatetime,vsurfdata.size());
return true;
}
在main函数中加入
if (strstr(argv[4],"xml")!=0) CrtSurfFile(argv[2],"xml"); // 把容器vsurfdata中的全国气象站点分钟观测数据写入文件。
if (strstr(argv[4],"json")!=0) CrtSurfFile(argv[2],"json");
if (strstr(argv[4],"csv")!=0) CrtSurfFile(argv[2],"csv");
在/tmp/idc/surfdata中查看导出文件
查看csv文件
json和xml文件格式举例
main中添加输入xml和json格式的代码
if (strcmp(datafmt,"xml")==0) File.Fprintf("<data>\n");
if (strcmp(datafmt,"json")==0) File.Fprintf("{\"data\":[\n");
for (int ii=0;ii<vsurfdata.size();ii++)// 遍历存放观测数据的vsurfdata容器。
{
if (strcmp(datafmt,"csv")==0)// 写入一条记录。
File.Fprintf("%s,%s,%.1f,%.1f,%d,%d,%.1f,%.1f,%.1f\n",\
vsurfdata[ii].obtid,vsurfdata[ii].ddatetime,vsurfdata[ii].t/10.0,vsurfdata[ii].p/10.0,\
vsurfdata[ii].u,vsurfdata[ii].wd,vsurfdata[ii].wf/10.0,vsurfdata[ii].r/10.0,vsurfdata[ii].vis/10.0);
if (strcmp(datafmt,"xml")==0)
File.Fprintf("<obtid>%s</obtid><ddatetime>%s</ddatetime><t>%.1f</t><p>%.1f</p>"\
"<u>%d</u><wd>%d</wd><wf>%.1f</wf><r>%.1f</r><vis>%.1f</vis><endl/>\n",\
vsurfdata[ii].obtid,vsurfdata[ii].ddatetime,vsurfdata[ii].t/10.0,vsurfdata[ii].p/10.0,\
vsurfdata[ii].u,vsurfdata[ii].wd,vsurfdata[ii].wf/10.0,vsurfdata[ii].r/10.0,vsurfdata[ii].vis/10.0);
if (strcmp(datafmt,"json")==0)
{
File.Fprintf("{\"obtid\":\"%s\",\"ddatetime\":\"%s\",\"t\":\"%.1f\",\"p\":\"%.1f\","\
"\"u\":\"%d\",\"wd\":\"%d\",\"wf\":\"%.1f\",\"r\":\"%.1f\",\"vis\":\"%.1f\"}",\
vsurfdata[ii].obtid,vsurfdata[ii].ddatetime,vsurfdata[ii].t/10.0,vsurfdata[ii].p/10.0,\
vsurfdata[ii].u,vsurfdata[ii].wd,vsurfdata[ii].wf/10.0,vsurfdata[ii].r/10.0,vsurfdata[ii].vis/10.0);
if (ii<vsurfdata.size()-1) File.Fprintf(",\n");
else File.Fprintf("\n");
}
查看xml和json文件
使用服务调度程序procct1自动生成测试数据
-
服务程序由调度程序周期性启动
-
想要使crtsurfdata脚本自动化运行【输出三种格式的气象数据文件】,这里利用了Linux的多进程和信号调度的策略,给出源码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
if(argc < 3)
{
printf("Using:./procct1 timev1 program argv ...\n");
printf("Example:/project/tools1/bin/procct1 5 /usr/bin/tar zcvf /tmp/program/tmp.tgz /usr/include\n\n");
printf("本程序是服务程序的调度程序,周期性启动服务程序或shell脚本. \n");
printf("timetvl 运行周期,单位:秒。 被调度的程序运行结束后,在timetv1秒后会被procct1重新启动\n");
printf("program 被调度的程序名称,必须使用全路径\n");
printf("argvs 被调度的程序参数\n");
printf("注意,本程序不会被kill杀死,但可以用kill -9强行杀死 \n\n\n");
return -1;
}
//先执行fork函数,创建一个子进程,让子进程调用execl执行新的程序,
//新程序将替换子进程,不会影响父进程,
//在父进程中,可以调用wait函数等待新程序运行的结果,这样就可以实现调度的功能
//程序实现功能 ./procct1 5 /usr/bin/ls -lt /tmp/bak.zip
for(int ii=0 ;ii<64 ;ii++)
{//程序员会先屏蔽掉全部的信号
signal(ii,SIG_IGN);
close(ii);
}
if(fork()!=0) exit(0);//生成子进程,父进程退出,让程序运行在后台,由系统1号进程托管.
signal(SIGCHLD,SIG_DFL);//启用SIGCHLD信号,让父进程可以wait子进程退出的状态
char *pargv[argc];
for(int ii=2 ;ii<argc;ii++)
pargv[ii-2]=argv[ii];
pargv[argc-2]=NULL;
while(true)
{
if(fork() == 0) //子进程
{
execv(argv[2],pargv);
//execl("/usr/bin/ls","/usr/bin/ls","-lt","/tmp/bak.zip",(char*)0);
//execl:把当前进程影像替换为新的进程影像(正文段,数据段,堆栈)
exit(0);
}
else //父进程
{
int status;
wait(&status);
sleep(atoi(argv[1]));
}
}
execl("/usr/bin/ls","/usr/bin/ls","-lt","/tmp/bak.zip",(char*)0);
//execl:把当前进程影像替换为新的进程影像(正文段,数据段,堆栈)
return 0;
}
设置时间参数是60s,每60s跑一编crtsurfdata
查看日志
可见,生成周期是60s,每1min生成一批测试数据文件。