C/C++11天气APP:txt/xml文件处理入库(psurfdata.cpp,_shqx.h),数据结构设计(PowerDesigner)

Posted 码农编程录

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++11天气APP:txt/xml文件处理入库(psurfdata.cpp,_shqx.h),数据结构设计(PowerDesigner)相关的知识,希望对你有一定的参考价值。


1.txt/xml文件入表/自身调度:结构体内容

// makefile
#oracle头文件路径
ORAINCL = -I$(ORACLE_HOME)/rdbms/public

# oracle库文件路径
ORALIB =  -L$(ORACLE_HOME)/lib -L.

# oracle的oci库
ORALIBS = -lclntsh

CC=g++
CFLAGS = -g -Wno-write-strings -Wno-unused-variable

all:crtsurfdata libftp.a demo18 ftpgetfile psurfdata

libftp.a:ftplib.c
        gcc -c -o libftp.a ftplib.c

demo18:demo18.cpp _ftp.h _ftp.cpp libftp.a
        g++ $(CFLAGS) -o demo18 demo18.cpp _public.cpp _ftp.cpp libftp.a

ftpgetfile:ftpgetfile.cpp _ftp.h _ftp.cpp libftp.a
        $(CC) $(CFLAGS) -o ftpgetfile ftpgetfile.cpp _public.cpp _ftp.cpp libftp.a
        cp ftpgetfile ../bin/.

crtsurfdata:crtsurfdata.cpp _public.h _public.cpp
        $(CC) $(CFLAGS) -o crtsurfdata crtsurfdata.cpp _public.cpp
        cp crtsurfdata ../bin/.

psurfdata:psurfdata.cpp _public.h _public.cpp
        g++ $(CFLAGS) -o psurfdata psurfdata.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _public.cpp _ooci.cpp
        cp psurfdata ../bin/.
        
clean:
        rm -rf crtsurfdata demo18 ftpgetfile libftp psurfdata
//psurfdata.cpp未封装成类
//本程序用于处理全国气象站点观测的分钟数据,并保存到数据库的T_SURFDATA表中。txt文件里面内容以逗号分隔
#include "_public.h"
#include "_ooci.h"
struct st_surfdata  // 全国气象站点分钟观测数据结构

  char obtid[11];      // 站点代码
  char ddatetime[21];  // 数据时间:格式yyyy-mm-dd hh:mi:ss。
  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米
;
CLogFile logfile;
CDir Dir;
bool _psurfdata(); // 处理数据文件
connection conn;
void EXIT(int sig);

int main(int argc,char *argv[])

  if (argc!=5)
  
    printf("\\n本程序用于处理全国气象站点观测的分钟数据,并保存到数据库的T_SURFDATA表中。\\n");
    printf("/oracle/lian/qxidc/bin/psurfdata 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\\n");
    printf("例如:/oracle/lian/qxidc/bin/psurfdata /oracle/lian/qxidc/tmp /oracle/lian/qxidc/log/psurfdata.log scott/tiger@snorcl11g_138 10\\n");
    return -1; //失败跳出main函数,必须在装有oracle主机中运行,不然_ooci中路径报错
  
  CloseIOAndSignal();   // 关闭全部的信号和输入输出  
  signal(SIGINT,EXIT); signal(SIGTERM,EXIT); // 处理程序退出的信号
  if (logfile.Open(argv[2],"a+")==false)
  
    printf("打开日志文件失败(%s)。\\n",argv[2]); return -1;
  
  logfile.Write("程序启动。\\n");
  while (true)
  
//1111111111111111111111111111111111111111111111111.扫描数据文件存放的目录
    //logfile.Write("开始扫描目录。\\n"); //打开目录拿到文件名放入string型容器里,需排序的话就把这容器排序(先生成先处理)
    if (Dir.OpenDir(argv[1],"SURF_ZH_*.txt",1000,true,true)==false) //OpenDir第四个参数是否打开子目录,第五个参数是否排序
    
      logfile.Write("Dir.OpenDir(%s) failed.\\n",argv[1]); sleep(atoi(argv[4])); continue;
    

//11111111111111111111111111111111111111111111111.逐个处理目录中的数据文件
    while (true)
    
      if (Dir.ReadDir()==false) break; //false为读完了
//logfile.Write("%s,%s,%s,%d,%s,%s,%s,%s\\n",Dir.m_DirName,Dir.m_FileName,Dir.m_FullFileName,Dir.m_FileSize,Dir.m_ModifyTime,Dir.m_CreateTime,Dir.m_AccessTime);

//111111111111111111111111111111111111111111111111.连接数据库
	  if (conn.m_state==0)  //0未连接
      
        if (conn.connecttodb(argv[3],"Simplified Chinese_China.ZHS16GBK")!=0)
        
          logfile.Write("connect database(%s) failed.\\n%s\\n",argv[3],conn.m_cda.message); break;
        // logfile.Write("连接数据库成功。\\n");
		
      
    
//1111111111111111111111111111111111111111111111111.处理入库
	  logfile.Write("开始处理文件%s...",Dir.m_FileName); //开头有时间
      if (_psurfdata()==false) 
      
        logfile.WriteEx("失败。\\n"); break;
            
      logfile.WriteEx("成功。\\n"); //不写时间,不换行,显示屏一行放不下
        
    if (conn.m_state==1) conn.disconnect();  //断开与数据库的连接
    sleep(atoi(argv[4]));
  
  return 0;

void EXIT(int sig)

  logfile.Write("程序退出,sig=%d\\n\\n",sig);
  exit(0);

      
//1111111111111111111111111111111111111111111111.处理入库
bool _psurfdata()

  CFile File; //打开文件
  if (File.Open(Dir.m_FullFileName,"r")==false)  //Dir的成员变量m_FullFileName也叫属性
  
    logfile.Write("(File.Open(%s) failed.\\n",Dir.m_FullFileName); return false;
  
  char strBuffer[301];
  CCmdStr CmdStr;
  struct st_surfdata stsurfdata;//定义stsurfdata结构体变量
  int iccount=0;  //int型初始化
  
  sqlstatement stmtsel(&conn);//select * 返回多行多列的结果集,bindin绑定选择行,bindout绑定选择列  
  stmtsel.prepare("select count(*) from T_SURFDATA where obtid=:1 and ddatetime=to_date(:2,'yyyy-mm-dd hh24:mi:ss')");
  stmtsel.bindin( 1, stsurfdata.obtid,5); // 定义的是字符串不用&
  stmtsel.bindin( 2, stsurfdata.ddatetime,19);
  stmtsel.bindout(1,&iccount); //select count(*)返回行数即一个数字赋给iccount这个变量,这个数字也是1列,所以bindout中1对应这列

  sqlstatement stmtins(&conn);
  stmtins.prepare("insert into T_SURFDATA(obtid,ddatetime,t,p,u,wd,wf,r,vis) values(:1,to_date(:2,'yyyy-mm-dd hh24:mi:ss'),:3,:4,:5,:6,:7,:8,:9)");
  stmtins.bindin( 1, stsurfdata.obtid,5); //1对应:1  //,crttime,keyid  //values里可加:,sysdate,SEQ_SURFDATA.nextval
  stmtins.bindin( 2, stsurfdata.ddatetime,19);
  stmtins.bindin( 3,&stsurfdata.t);
  stmtins.bindin( 4,&stsurfdata.p);
  stmtins.bindin( 5,&stsurfdata.u);
  stmtins.bindin( 6,&stsurfdata.wd);
  stmtins.bindin( 7,&stsurfdata.wf);
  stmtins.bindin( 8,&stsurfdata.r);
  stmtins.bindin( 9,&stsurfdata.vis);

  while (true) //读取文件中的每一行记录并写入数据库的表中
  
    memset(strBuffer,0,sizeof(strBuffer));
    if (File.Fgets(strBuffer,300,true)==false) break; //Fgets从文件中读取一行放入strBuffer,第三个参数为是否删除最后空格
    // logfile.Write("%s\\n",strBuffer); strBuffer内容为58436,2020-02-09 12:11:00,32.4,1006.9,99,249,11.8,0.2,10107.3
    CmdStr.SplitToCmd(strBuffer,",",true); //以,号拆分成9个片段存入CmdStr中
    if (CmdStr.CmdCount()!=9)
    
      logfile.Write("%s\\n",strBuffer); continue;
    
    memset(&stsurfdata,0,sizeof(struct st_surfdata)); //sizeof里一般用结构体类型,传变量名的话若是指针就不好了
    CmdStr.GetValue(0,stsurfdata.obtid,5);      // 站点代码 赋值给stsurfdata.obtid
    CmdStr.GetValue(1,stsurfdata.ddatetime,19); // 数据时间:格式yyyy-mm-dd hh:mi:ss。
    double dtmp=0;
    CmdStr.GetValue(2,&dtmp); stsurfdata.t=(int)(dtmp*10);  // 气温:单位,0.1摄氏度
    CmdStr.GetValue(3,&dtmp); stsurfdata.p=(int)(dtmp*10);  // 气压:0.1百帕
    CmdStr.GetValue(4,&stsurfdata.u);  // 相对湿度,0-100之间的值。
    CmdStr.GetValue(5,&stsurfdata.wd); // 风向,0-360之间的值。
    CmdStr.GetValue(6,&dtmp); stsurfdata.wf=(int)(dtmp*10);  // 风速:单位0.1m/s
    CmdStr.GetValue(7,&dtmp); stsurfdata.r=(int)(dtmp*10);   // 降雨量:0.1mm
    CmdStr.GetValue(8,&dtmp); stsurfdata.vis=(int)(dtmp*10); // 能见度:0.1米
    if (stmtsel.execute() != 0)
    
      logfile.Write("stmtsel.execute() failed.\\n%s\\n%s\\n",stmtsel.m_sql,stmtsel.m_cda.message); 
      if ( (stmtsel.m_cda.rc>=3113) && (stmtsel.m_cda.rc<=3115) ) return false; //3113-3115是数据库连接失败       
      continue;
    
    iccount=0;
    stmtsel.next(); //把"select count(*)....."这个sql查询结果一次一次取结果集赋给绑定输出的变量即iccount
    //这里比较特殊刚好一行一列即一个数字
    if (iccount>0) continue; //有记录不执行插入

    if (stmtins.execute() != 0)  // 执行SQL语句,一定要判断返回值,0-成功,其它-失败
     //往数据库里插入,如果记录存在不应该退出,应该跳过已存在的记录
      if (stmtins.m_cda.rc!=1) //!=1才是真正的失败,=1是主键冲突,若是主键冲突可以跳过不入库不要返回失败
      
        logfile.Write("%s\\n",strBuffer);
        logfile.Write("stmtins.execute() failed.\\n%s\\n%s\\n",stmtins.m_sql,stmtins.m_cda.message); 
        if ( (stmtins.m_cda.rc>=3113) && (stmtins.m_cda.rc<=3115) ) return false;
      
    
  
//处理生成数据就是先扫描目录,读取目录下文件。读到文件名后打开一文件,一行一行解析出数据插入数据库表里,关闭文件,提交事务
  conn.commit();
  // 关闭文件指针,并删除文件,不删除会重复读取
  File.CloseAndRemove(); 
  return true;



vi psurfdata.log,如下子目录下的文件也读取到了。

如下在_psurfdata()里思路是读一行,按,号拆分,将每个内容读出来再*10放入数据库。


vi /htidc/shqx/ini/stcode1.ini 。

在_shqx.cpp中有InsertTable()成员函数,有select,insert,update及各个的execute()。如下如果记录在表里已存在就执行stmtupt.execute(),不存在就执行stmtins.execute(),不管是这两个执行,只要出错,无效的记录数invalidcount就+1,成功的话updatacount和insertcount都+1。


如下时间和文件名一样,但站点不一样 ,59287这个站点是存在的即外键存在。

以下是自身的调度:1.以下将psurfdata.cpp改为程序自身调度,不用crontab调度。每10秒钟扫描一次目录,有文件的话就连接数据库。

如下为什么不在while(true)扫描目录前连上数据库?假设数据一分钟生成一个文件,处理一个文件入库一秒不到,所以一直连着数据库浪费资源,扫描到有文件处理就连数据库。

如下数据库没连上也不用return -1,只要psurfdata.cpp启动后就一直运行,遇到错误也不能退出,所以改为break只跳出这个小循环,继续往下面执行,日志还是会写“connect database…failed”。

2.以下crtsurfdata中自身调度。

结构体可存不同数据类型,需解析xml,将值放入结构体再访问。start.sh里面放crt.,ftp.,p…三个启动脚本并最后加&符。

//将psurfdata.cpp,txt文件入库封成类
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
CLogFile logfile;
CDir Dir;
bool _psurfdata();
connection conn; //实例化对象,con也叫变量(称呼)
void EXIT(int sig);

int main(int argc,char *argv[])

  if (argc!=5)
  
    printf("\\n本程序用于处理全国气象站点观测的分钟数据,并保存到数据库的T_SURFDATA表中。\\n");
    printf("这是完善后的程序,未完善的程序在psurfdata_old.cpp中。\\n");
    printf("/htidc/shqx/bin/psurfdata 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\\n");
    printf("例如:/htidc/shqx/bin/psurfdata /data/shqx/sdata/surfdata /log/shqx/psurfdata.log shqx/pwdidc@snorcl11g_198 10\\n");
    return -1;
  
  CloseIOAndSignal();
  signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[2],"a+")==false)
  
    printf("打开日志文件失败(%s)。\\n",argv[2]); return -1;
  
  logfile.Write("程序启动。\\n");
  while (true)
      
//111111111111111111111111111111111111111111111.扫描数据文件存放的目录,只匹配"SURF_ZH_*.txt"
	// logfile.Write("开始扫描目录。\\n");
    if (Dir.OpenDir(argv[1],"SURF_ZH_*.txt",1000,true,true)==false)
    
      logfile.Write("Dir.OpenDir(%s) failed.\\n",argv[1]); sleep(atoi(argv[4])); continue;
    

//11111111111111111111111111111111111111111111111.连接数据库
    while (true)
    
      if (Dir.ReadDir()==false) break;  
      if (conn.m_state==0)
      
        if (conn.connecttodb(argv[3],"Simplified Chinese_China.ZHS16GBK")!=0)
        
          logfile.Write("connect database(%s) failed.\\n%s\\n",argv[3],conn.m_cda.message); break;
        
        // logfile.Write("连接数据库成功。\\n");
        
      logfile.Write("开始处理文件%s...",Dir.m_FileName);
    
//111111111111111111111111111111111111111111111111.处理入库
      if (_psurfdata()==false) 
      
        logfile.WriteEx("失败。\\n"); break;
      
    
    if (conn.m_state==1) conn.disconnect(); // 断开与数据库的连接
    sleep(以上是关于C/C++11天气APP:txt/xml文件处理入库(psurfdata.cpp,_shqx.h),数据结构设计(PowerDesigner)的主要内容,如果未能解决你的问题,请参考以下文章

AWS SES S3 处理入站电子邮件

C/C++14天气APP:文件传输系统(tcpput/getfile.cpp客户端,tcpfileserver.cpp)

使用 node.js 处理入站 Twilio 消息

javascript 入站操作 - 处理和处理入站电子邮件

C/C++10天气APP:MySQL,PostgreSQL,环境变量,动静态库,Linux/Oracle字符集

C/C++9天气APP:Oracle的虚表/日期/序列,索引/视图/链路/同义词,数据库高可用性