【C/C++】项目_7_不同数据建表入表,计算,交换子系统(exptables.cpp,ftpputfiles.cpp)

@TOC


1.csv和xml文件:< data >< end1/>,FGETS

以逗号分隔的文件也叫csv,.txt后缀可改为.csv后缀,下面是excel软件打开.txt文件


在这里插入图片描述

txt文件字段顺序和个数需要固定且换行时也不好处理。如下是xml标准格式,前后加< data >标签,每行后加< end1/>,只有标准格式才能用浏览器打开显示


在这里插入图片描述

vi crtsurfdata1.cpp(支持生成xml和txt两种文件)
在这里插入图片描述

之前以逗号分隔,下面这个支持xml,vi psurfdata1.cpp


在这里插入图片描述

在这里插入图片描述

2.分区预警信号数据:UpdateStr,AddTime

2.1 数据说明

在这里插入图片描述

下面为说明文档:


在这里插入图片描述

2.2 建表入表

下面左表站点代码改为街道代码,站点名称改为街道名称


在这里插入图片描述

在这里插入图片描述
// psignallog.cpp封成类
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
CLogFile logfile;
CDir Dir;
// 处理数据文件
bool _psignallog();
connection conn;
void EXIT(int sig);
int main(int argc,char *argv[])
{
  if (argc!=5)
  {
    printf("\n本程序用于处理分区预警信号发布日志,并保存到数据库的T_SIGNALLOG表中。\n");
    printf("/oracle/htidc/shqx/bin/psignallog 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\n");
    printf("例如:/oracle/htidc/shqx/bin/psignallog /oracle/data/shqx/sdata/wpfiles /oracle/log/shqx/psignallog.log shqx/pwdidc@snorcl11g_128 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)
  {
    // logfile.Write("开始扫描目录。\n");
    // 扫描数据文件存放的目录,只匹配"WP20*.DTB"
    if (Dir.OpenDir(argv[1],"WP20*.DTB",1000,true,true)==false)
    {
      logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]); sleep(atoi(argv[4])); continue;
    }
    // 逐个处理目录中的数据文件
    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);  
      // 处理数据文件
      if (_psignallog()==false) 
      {
        logfile.WriteEx("失败。\n"); break;
      }
    }
    // 断开与数据库的连接
    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);
}
     
// 处理数据文件
bool _psignallog()
{
  // 打开文件
  CFile File;
  if (File.Open(Dir.m_FullFileName,"r")==false)
  {
    logfile.Write("(File.Open(%s) failed.\n",Dir.m_FullFileName); return false;
  }
  CSIGNALLOG SIGNALLOG(&conn,&logfile);
  // 读取文件中的每一行记录
  // 写入数据库的表中
  char strBuffer[301];
  while (true)
  {
    memset(strBuffer,0,sizeof(strBuffer));
    // 从文件中获取一行记录
    if (File.Fgets(strBuffer,300,true)==false) break;
    // 每行预警信号发布的记录的最后都是用"000="结束的。不会得到第一,二行和最后一行
    if (strstr(strBuffer,"000=")==0) continue;
    UpdateStr(strBuffer,"  "," ",true);  // 把内容中的两个空格替换成一个空格
    // logfile.Write("%s\n",strBuffer);    
    // 把用逗号分隔的记录拆分到结构体中
    if (SIGNALLOG.SplitBuffer(strBuffer)==false) { logfile.Write("%s\n",strBuffer); continue; }
    // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
    long rc=SIGNALLOG.InsertTable();
    // 只要不是数据库session的错误,程序就继续。
    if ( (rc>=3113) && (rc<=3115) ) return false;
    if (rc != 0) { logfile.Write("%s\n",strBuffer); continue; }
  }
  // 提交事务
  conn.commit();
  // 关闭文件指针,并删除文件
  File.CloseAndRemove();
  logfile.WriteEx("成功(total=%d,insert=%d,update=%d,invalid=%d)。\n",SIGNALLOG.totalcount,SIGNALLOG.insertcount,SIGNALLOG.updatecount,SIGNALLOG.invalidcount);
  return true;
}

关于_shqx.h(增加了struct st_signallog结构体)和_shqx.cpp见文章:https://blog.csdn.net/weixin_43435675/article/details/103476761

在这里插入图片描述

WP...0510.DTB时间是05:10:00下面是加了8小时
在这里插入图片描述

下面为全拷进去进行插入数据库
在这里插入图片描述

3.台风(热带气旋)数据:基信,实路

3.1 数据说明

第一行第四个:开始依次气旋序号cyclone(001),国内编号num(1801),热带气旋终结标志ws(0),每行路径间隔小时数hours(6),热带气旋的英文名称t_name(BOLAVEN),数据集形成的日期datasettime(20190319)。
第二行第一个:YYYY年MM月DD日HH时ddatetime(世界时2018021000),强度标记h_level(1),纬度lat(84),经度lon(1435),中心最低气压pres(1008),2分钟平均近中心最大风速wnd(13),(2分钟平均风速owd)。

在这里插入图片描述

1.头记录(第一行)格式如下:
在这里插入图片描述

2.实况路径(第二行往下)(不是预报路径)数据记录格式如下:
在这里插入图片描述

在这里插入图片描述

3.2 建表入表

在这里插入图片描述

实况路径台风在海上哪边就是哪,然而有发布台代号是因为不同台通过卫星对台风经纬度定位也有差别
在这里插入图片描述

如下tsid从1,2从小到大往后排
在这里插入图片描述

在这里插入图片描述

如下fcid是北京发布,按时间推移在移动。如下主键是气旋编号tsid+数据时间ddatetime,也就是可以查看相同tsid和ddatetime不同fcid经纬度差别,说明不同发布台对台风位置定位不准
在这里插入图片描述

下面是台风路径预报数据:大概是什么时候将会到哪里,风速多少这些信息
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

// typthoon.cpp
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
CLogFile logfile;
CDir Dir;
// 处理数据文件
bool _typthon();
connection conn;
void EXIT(int sig);

int main(int argc,char *argv[])
{
  if (argc!=5)
  {
    printf("\n本程序用于处理分区预警信号发布日志,并保存到数据库的T_SIGNALLOG表中。\n");
    printf("/oracle/htidc/shqx/bin/typthon 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\n");
    printf("例如:/oracle/htidc/shqx/bin/typthon /oracle/data/shqx/sdata/typthon /oracle/log/shqx/typthon.log shqx/pwdidc@snorcl11g_128 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)
  {
     logfile.Write("开始扫描目录。\n");
    // 扫描数据文件存放的目录,只匹配"CH20*.DTB"
    if (Dir.OpenDir(argv[1],"CH*.TXT",1000,true,true)==false)
    {
      logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]); sleep(atoi(argv[4])); continue;
    }
    // 逐个处理目录中的数据文件
    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);  
      // 处理数据文件
      if (_typthon()==false) 
      {
        logfile.WriteEx("失败。\n"); break;
      }
    }
    // 断开与数据库的连接
    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);
}
     
//处理数据文件
bool _typthon()
{
  // 打开文件
  CFile File;
  if (File.Open(Dir.m_FullFileName,"r")==false)
  {
    logfile.Write("(File.Open(%s) failed.\n",Dir.m_FullFileName); return false;
  }
  CTYPTHOON TYPTHON(&conn,&logfile);
  // 读取文件中的每一行记录
  // 写入数据库的表中
  char strBuffer[301];
  while (true)
  {
    memset(strBuffer,0,sizeof(strBuffer));
    // 从文件中获取一行记录
    if (File.Fgets(strBuffer,300,true)==false) break;
    UpdateStr(strBuffer,"  "," ",true);  // 把内容中的两个空格替换成一个空格
    // logfile.Write("%s\n",strBuffer);    
    // 把用逗号分隔的记录拆分到结构体中
    if (TYPTHON.SplitBuffer(strBuffer)==false) { logfile.Write("%s拆分失败\n",strBuffer); continue; }
    // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
    long rc=TYPTHON.InsertTable();
    // 只要不是数据库session的错误,程序就继续。
    if ( (rc>=3113) && (rc<=3115) ) return false;
    if (rc != 0) { logfile.Write("%s\n",strBuffer); continue; }
  }
  // 提交事务
  conn.commit();
  // 关闭文件指针,并删除文件
  File.CloseAndRemove();
  logfile.WriteEx("成功(total=%d,insert=%d,update=%d,invalid=%d)。\n",TYPTHON.totalcount,TYPTHON.insertcount,TYPTHON.updatecount,TYPTHON.invalidcount);
  return true;
}
//_shqx.h
#ifndef _SHQX_H
#define _SHQX_H
#include "_public.h"
#include "_ooci.h"
//台风数据结构
struct st_typthoon1
{ 
  char ddatetime[21];   // YYYY年, MM月, DD日,HH时(世界时);
  char h_level[2];      //强度标记
  double lat;          // 纬度
  double lon;          // 经度
  char pres[2];     //中心最低气压(hPa);
  int  wnd;     //2分钟平均近中心最大风速(MSW, m/s)
  int  owd;     //2分钟平均风速(m/s)
  int t_no;  //自定义台风编号,从第0个开始
};
struct st_typthoon
{
  char cyclone[5];       //气旋序号
  char num[5];        //国内编号
  char ws[2];            //热带气旋终结标志
  char hours[2];         //每行路径间隔小时数, 目前均为6(小时);
  char t_name[30];         //热带气旋的英文名称, 名称后加 “(-1)n” 表示副中心及其序号;
  char datasettime[21];  //数据集形成的日期
};
class CTYPTHOON
{
public:
  int totalcount,insertcount,updatecount,invalidcount;  // 记录总数据、插入数、更新数、无效记录数。
  int c;//个数
  struct st_typthon m_sttypthon;
  struct st_typthon1 m_sttypthon1;
  vector<struct st_typthon> vtypthon;   // 容器存放一个文件的全部记录
  CTYPTHON(connection *conn,CLogFile *logfile);
 ~CTYPTHON();
  void initdata();  // 数据初始化

  connection *m_conn;
  CLogFile   *m_logfile;
  int iccount;
  sqlstatement stmtsel,stmtins,stmtupt;
  // 把记录拆分到vsignallog容器中。
  bool SplitBuffer(const char *strBuffer);
  // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
  long InsertTable();
};
#endif
//_shqx.cpp
#include "_shqx.h"
CTYPTHON::CTYPTHON(connection *conn,CLogFile *logfile)
{
  initdata();
  m_conn=conn; m_logfile=logfile;
}
void CTYPTHON::initdata()
{
  totalcount=insertcount=updatecount=invalidcount=0;
  m_conn=0; m_logfile=0;
  memset(&m_sttypthon,0,sizeof(struct st_typthon));
  memset(&m_sttypthon1,0,sizeof(struct st_typthon1));
}
CTYPTHON::~CTYPTHON()
{
}
// 把用逗号分隔的记录拆分到m_sttypthon结构中。
bool CTYPTHON::SplitBuffer(const char *strBuffer)
{
  totalcount++;
//  memset(&m_sttypthon1,0,sizeof(struct st_typthon));
  CCmdStr CmdStr;
  CmdStr.SplitToCmd(strBuffer," ",true);
  c= CmdStr.CmdCount();
  if(CmdStr.CmdCount()==9)
  {
    memset(&m_sttypthon,0,sizeof(struct st_typthon));
    CmdStr.GetValue(3,m_sttypthon.cyclone,4); 
    CmdStr.GetValue(4,m_sttypthon.num,4); 
    CmdStr.GetValue(5,m_sttypthon.ws,1); 
    CmdStr.GetValue(6,m_sttypthon.hours,1); 
    CmdStr.GetValue(7,m_sttypthon.t_name,29); 
    CmdStr.GetValue(8,m_sttypthon.datasettime,19); 

  }
  if (CmdStr.CmdCount()==6)
  {
    memset(&m_sttypthon1,0,sizeof(struct st_typthon1));
    CmdStr.GetValue(0,m_sttypthon1.ddatetime,10); // 数据时间:格式yyyymmddhh24
    strcat(m_sttypthon1.ddatetime,"0000");
    AddTime(m_sttypthon1.ddatetime,m_sttypthon1.ddatetime,8*60*60,"yyyy-mm-dd hh24:mi:ss");
    CmdStr.GetValue(1,m_sttypthon1.h_level,1);
    double dtmp=0;int ii=0;
    CmdStr.GetValue(2,&dtmp); m_sttypthon1.lat=dtmp; 
    CmdStr.GetValue(3,&dtmp); m_sttypthon1.lon=dtmp;  
    CmdStr.GetValue(4,m_sttypthon1.pres,1);
    CmdStr.GetValue(5,&ii); m_sttypthon1.wnd=ii;
    CmdStr.GetValue(5,&ii); m_sttypthon1.owd=ii;
    
  }
  //判断是不是同一个台风,根据2分钟平均风速*30*60  每小时小于20公里来判断
 // if (CmdStr.CmdCount()!=6 && CmdStr.CmdCount()!=9) 
 //{ invalidcount++; return false; }
  if(CmdStr.CmdCount()==9) {invalidcount++;}
  return true;
}

long CTYPTHON::InsertTable()
{
  if (stmtsel.m_state==0)
  {
    stmtsel.connect(m_conn);
    stmtsel.prepare("select count(*) from T_TYPTHON where cyclone=:1 and t_name=:2 and ddatetime=to_date(:3,'yyyy-mm-dd hh24:mi:ss')");
    stmtsel.bindin( 1, m_sttypthon.cyclone,4);
    stmtsel.bindin( 2, m_sttypthon.t_name,29);
    stmtsel.bindin( 3, m_sttypthon1.ddatetime,20);
    stmtsel.bindout(1,&iccount);
    //m_logfile->Write("\nt_name==%s\n,ddatetime==%s",m_sttypthon.t_name,m_sttypthon1.ddatetime); 
  }
  if (stmtins.m_state==0)
  {
    stmtins.connect(m_conn);
    stmtins.prepare("insert into T_TYPTHON(cyclone,num,ws,hours,t_name,datasettime,ddatetime,h_level,lat,lon,pres,wnd,owd,crttime,keyid) values(:1,:2,:3,:4,:5,to_date(:6,'yyyy-mm-dd'),to_date(:7,'yyyy-mm-dd hh24:mi:ss'),:8,:9,:10,:11,:12,:13,sysdate,SEQ_TYPTHON.nextval)");
    stmtins.bindin( 1, m_sttypthon.cyclone,4);
    stmtins.bindin( 2, m_sttypthon.num,4);
    stmtins.bindin( 3, m_sttypthon.ws,1);
    stmtins.bindin( 4, m_sttypthon.hours,4);
    stmtins.bindin( 5, m_sttypthon.t_name,29);
    stmtins.bindin( 6, m_sttypthon.datasettime,20);
    stmtins.bindin( 7, m_sttypthon1.ddatetime,20);
    stmtins.bindin( 8, m_sttypthon1.h_level,1);
    stmtins.bindin( 9, &m_sttypthon1.lat);
    stmtins.bindin( 10, &m_sttypthon1.lon);
    stmtins.bindin( 11, m_sttypthon1.pres,1);
    stmtins.bindin( 12, &m_sttypthon1.wnd);
    stmtins.bindin( 13, &m_sttypthon1.owd);
    //m_logfile->Write(" 插入%s,%s,%s,%s,%s,%s,%s,%s,%lf,%lf,%s,%d,%d\n",m_sttypthon.cyclone,m_sttypthon.num,m_sttypthon.ws,m_sttypthon.hours,m_sttypthon.t_name,m_sttypthon.datasettime,m_sttypthon1.ddatetime,m_sttypthon1.h_level,m_sttypthon1.lat,m_sttypthon1.lon,m_sttypthon1.pres,m_sttypthon1.wnd,m_sttypthon1.owd);
  }
  if (stmtupt.m_state==0)
  {
    stmtupt.connect(m_conn);
    stmtupt.prepare("update T_TYPTHON set ddatetime=to_date(:1,'yyyy-mm-dd hh24:mi:ss'),h_level=:2,lat=:3,lon=:4,pres=:5,owd=:6,wnd=:7 where cyclone=:8 and t_name=:9 and ddatetime=to_date(:10,'yyyy-mm-dd hh24:mi:ss')");
    stmtupt.bindin( 1, m_sttypthon1.ddatetime,20);
    stmtupt.bindin( 2, m_sttypthon1.h_level,1);
    stmtupt.bindin( 3, &m_sttypthon1.lat);
    stmtupt.bindin( 4, &m_sttypthon1.lon);
    stmtupt.bindin( 5, m_sttypthon1.pres,1);
    stmtupt.bindin( 6, &m_sttypthon1.owd);
    stmtupt.bindin( 7, &m_sttypthon1.wnd);
    stmtupt.bindin( 8, m_sttypthon.cyclone,4);
    stmtupt.bindin( 9, m_sttypthon.t_name,29);
    stmtupt.bindin( 10, m_sttypthon1.ddatetime,20);
  }
  if (stmtsel.execute() != 0)
  {
    invalidcount++; 
    m_logfile->Write("stmtsel.execute() failed.\n%s\n%s\n",stmtsel.m_sql,stmtsel.m_cda.message); 
    //m_logfile->Write("%s,abcderf=%s",m_sttypthon.datasettime,m_sttypthon1.ddatetime);
    //m_logfile->Write("%s,==%s",m_sttypthon.t_name,m_sttypthon1.ddatetime); 
    return stmtsel.m_cda.rc;
  }  
  iccount=0;
  stmtsel.next();
   // 必须是正确的数据才进行插入和查询
  if(c==6){
  if (iccount>0) 
  {
    // 执行更新的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtupt.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("stmtupt.execute() failed.\n%s\n%s\n",stmtupt.m_sql,stmtupt.m_cda.message);
      return stmtupt.m_cda.rc;
    }
    updatecount++;
  }
  else
  {
    // 执行插入的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtins.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("stmtins.execute() failed.\n%s\n%s\n",stmtins.m_sql,stmtins.m_cda.message);
      return stmtins.m_cda.rc;
    }
    insertcount++;
  }
  }
  return 0;
}

4.云量观测仪数据:null

4.1 数据说明

主键为台站号和数据时间


在这里插入图片描述

在这里插入图片描述

5.全国预警信号JSON:表,记录

在这里插入图片描述

如上“surfdata”相当于第二个表。w1,2,3,4作为主键。http://www.360doc.com/content/18/0321/11/51484742_738963041.shtml

6.全国天气预报数据:999.9

核心,预报地区和时效精细化,如下文件名的信息不用太关心

在这里插入图片描述

在这里插入图片描述

如下从第四行product,foretime【世界时需加8小时,今天夜间就是今晚20点到明早08天,明天白天就是明天08点到晚上20点,2个时间段】,起报时间为00+8=08时,3为8+3=11点,6为8+6=14点...,168小时7天,遇到999替换为空。第六行obtid站号P5599,21为下面有21行。第七行依次:时次,温度,相对湿度.....
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

//forecast.cpp
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
CLogFile logfile;
CDir Dir;
// 处理数据文件
bool _forecast();
connection conn;
//void EXIT(int sig);
int main(int argc,char *argv[])
{
  if (argc!=5)
  {
    printf("\n本程序用于处理分区预警信号发布日志,并保存到数据库的T_FORECAST表中。\n");
    printf("/oracle/htidc/shqx/bin/forecast 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\n");
    printf("例如:/oracle/htidc/shqx/bin/forecast /oracle/data/shqx/sdata/forecast /oracle/log/shqx/forecast.log shqx/pwdidc@snorcl11g_128 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)
  {
     logfile.Write("开始扫描目录。\n");
    // 扫描数据文件存放的目录,只匹配"Z_*.DTB"
    if (Dir.OpenDir(argv[1],"Z_*.TXT",1000,true,true)==false)
    {
      logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]); sleep(atoi(argv[4])); continue;
    }
    // 逐个处理目录中的数据文件
    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);  
      // 处理数据文件
      if (_forecast()==false) 
      {
        logfile.WriteEx("失败。\n"); break;
      }
    }
    // 断开与数据库的连接
    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);
}
     
// 处理数据文件
bool _forecast()
{
  // 打开文件
  CFile File;
  if (File.Open(Dir.m_FullFileName,"r")==false)
  {
    logfile.Write("(File.Open(%s) failed.\n",Dir.m_FullFileName); return false;
  }
  CFORECAST FORECAST(&conn,&logfile);
  // 读取文件中的每一行记录
  // 写入数据库的表中
  char strBuffer[301];
  while (true)
  {
    memset(strBuffer,0,sizeof(strBuffer));
    // 从文件中获取一行记录
    if (File.Fgets(strBuffer,300,true)==false) break;
    UpdateStr(strBuffer,"  "," ",true);  // 把内容中的两个空格替换成一个空格
    // logfile.Write("%s\n",strBuffer);    
    // 把用逗号分隔的记录拆分到结构体中
    if (FORECAST.SplitBuffer(strBuffer)==false) { logfile.Write("%s拆分失败\n",strBuffer); continue; }
    // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
    long rc=FORECAST.InsertTable();
    // 只要不是数据库session的错误,程序就继续。
    if ( (rc>=3113) && (rc<=3115) ) return false;
    if (rc != 0) { logfile.Write("插入失败%s\n",strBuffer); continue; }
  }
  // 提交事务
  conn.commit();
  // 关闭文件指针,并删除文件
  File.CloseAndRemove();
  logfile.WriteEx("成功(total=%d,insert=%d,update=%d,invalid=%d)。\n",FORECAST.totalcount,FORECAST.insertcount,FORECAST.updatecount,FORECAST.invalidcount);
  return true;
}
//_shqx.h
#ifndef _SHQX_H
#define _SHQX_H
#include "_public.h"
#include "_ooci.h"
struct st_forecast
{
   char product[6];                                   
   char foretime[20];                                  
};
struct st_forecast1
{
   char obtid[6];                                     
};
struct st_forecast2
{
   char sx[4];                                        
   char wd[6];                   
   char csd[6];            
   char wind[6];                  
   char speed[6];                 
   char pressure[6];              
   char p[6]; 
   char cloud[6];                 
   char lcloud[6];                
   char weather[6];               
   char vis[6];                   
   char ht[6];                    
   char lt[6];                    
   char maxsd[6];                 
   char minsd[6];                 
   char p2[6];                    
   char p1[6];                    
   char c2[6];                    
   char c1[6];                    
   char weather1[6];             
   char wind1[6];                 
   char speed1[6];                
};
class CFORECAST
{
public:
  int totalcount,insertcount,updatecount,invalidcount;  // 记录总数据、插入数、更新数、无效记录数。
  struct st_forecast m_stforecast;
  struct st_forecast1 m_stforecast1;
  struct st_forecast2 m_stforecast2;
  CFORECAST(connection *conn,CLogFile *logfile);
 ~CFORECAST();
  void initdata();  // 数据初始化

  connection *m_conn;
  CLogFile   *m_logfile;
  int iccount;
  sqlstatement stmtsel,stmtins,stmtupt;
  // 把记录拆分到vsignallog容器中。
  bool SplitBuffer(const char *strBuffer);
  // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
  long InsertTable();
};
#endif
//_shqx.cpp
#include "_shqx.h"
CFORECAST::CFORECAST(connection *conn,CLogFile *logfile)
{
  initdata();
  m_conn=conn; m_logfile=logfile;
}
void CFORECAST::initdata()
{
  totalcount=insertcount=updatecount=invalidcount=0;
  m_conn=0; m_logfile=0;
  memset(&m_stforecast,0,sizeof(struct st_forecast));
  memset(&m_stforecast1,0,sizeof(struct st_forecast1));
  memset(&m_stforecast2,0,sizeof(struct st_forecast2));
}
CFORECAST::~CFORECAST()
{
}
// 把用逗号分隔的记录拆分到m_stforecast结构中。
bool CFORECAST::SplitBuffer(const char *strBuffer)
{
  totalcount++;
  CCmdStr CmdStr;
  CmdStr.SplitToCmd(strBuffer," ",true);
  c = CmdStr.CmdCount();
  if(CmdStr.CmdCount()==2)
  {
    memset(&m_stforecast,0,sizeof(struct st_forecast));
    CmdStr.GetValue(0,m_stforecast.product,5);
    CmdStr.GetValue(1,m_stforecast.foretime,10);
    strcat(m_stforecast.foretime,"0000");
    AddTime(m_stforecast.foretime,m_stforecast.foretime,8*60*60,"yyyy-mm-dd hh24:mi:ss");
  }
  if(CmdStr.CmdCount()==6)
  {
    memset(&m_stforecast1,0,sizeof(struct st_forecast1));
    CmdStr.GetValue(0,m_stforecast1.obtid,5); 
  }
  if (CmdStr.CmdCount()==22)
  {
    memset(&m_stforecast2,0,sizeof(struct st_forecast2));
    CmdStr.GetValue(0,m_stforecast2.sx,3);
    CmdStr.GetValue(1,m_stforecast2.wd,5); 
    CmdStr.GetValue(2,m_stforecast2.csd,5); 
    CmdStr.GetValue(3,m_stforecast2.wind,5);
    CmdStr.GetValue(4,m_stforecast2.speed,5);
    CmdStr.GetValue(5,m_stforecast2.pressure,5);
    CmdStr.GetValue(6,m_stforecast2.p,5); 
    CmdStr.GetValue(7,m_stforecast2.cloud,5);
    CmdStr.GetValue(8,m_stforecast2.lcloud,5); 
    CmdStr.GetValue(9,m_stforecast2.weather,5);
    CmdStr.GetValue(10,m_stforecast2.vis,5);
    CmdStr.GetValue(11,m_stforecast2.ht,5);
    CmdStr.GetValue(12,m_stforecast2.lt,5);
    CmdStr.GetValue(13,m_stforecast2.maxsd,5);
    CmdStr.GetValue(14,m_stforecast2.minsd,5);
    CmdStr.GetValue(15,m_stforecast2.p2,5);
    CmdStr.GetValue(16,m_stforecast2.p1,5);
    CmdStr.GetValue(17,m_stforecast2.c2,5);
    CmdStr.GetValue(18,m_stforecast2.c1,5);
    CmdStr.GetValue(19,m_stforecast2.weather1,5); 
    CmdStr.GetValue(20,m_stforecast2.wind1,5); 
    CmdStr.GetValue(21,m_stforecast2.speed1,5);
  }
  return true;
}
// 把m_stforecast结构中的值更新到T_FORECAST表中。
long CFORECAST::InsertTable()
{
  if (stmtsel.m_state==0)
  {
    stmtsel.connect(m_conn);
    stmtsel.prepare("select count(*) from T_FORECAST where product=:1 and foretime=to_date(:2,'yyyy-mm-dd hh24:mi:ss') and obtid=:3 and sx=:4");
    stmtsel.bindin(1,m_stforecast.product,5);
    stmtsel.bindin(2,m_stforecast.foretime,19);
    stmtsel.bindin(3,m_stforecast1.obtid,5);
    stmtsel.bindin(4,m_stforecast2.sx,3);
    stmtsel.bindout(1,&iccount);
  }
  if (stmtins.m_state==0)
  {
    stmtins.connect(m_conn);
    stmtins.prepare("insert into T_FORECAST values(:1,to_date(:2,'yyyy-mm-dd hh24:mi:ss'),:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16,:17,:18,:19,:20,:21,:22,:23,:24,:25,SEQ_FORECAST.nextval,sysdate)");
    stmtins.bindin( 1, m_stforecast.product,5);
    stmtins.bindin( 2, m_stforecast.foretime,19);
    stmtins.bindin( 3, m_stforecast1.obtid,5);
    stmtins.bindin( 4, m_stforecast2.sx,3);
    stmtins.bindin( 5, m_stforecast2.wd,5);
    stmtins.bindin( 6, m_stforecast2.csd,5);
    stmtins.bindin( 7, m_stforecast2.wind,5);
    stmtins.bindin( 8, m_stforecast2.speed,5);
    stmtins.bindin( 9, m_stforecast2.pressure,5);
    stmtins.bindin( 10,m_stforecast2.p,5);
    stmtins.bindin( 11,m_stforecast2.cloud,5);
    stmtins.bindin( 12,m_stforecast2.lcloud,5);
    stmtins.bindin( 13,m_stforecast2.weather,5);
    stmtins.bindin( 14,m_stforecast2.vis,5);
    stmtins.bindin( 15,m_stforecast2.ht,5);
    stmtins.bindin( 16,m_stforecast2.lt,5);
    stmtins.bindin( 17,m_stforecast2.maxsd,5);
    stmtins.bindin( 18,m_stforecast2.minsd,5);
    stmtins.bindin( 19,m_stforecast2.p2,5);
    stmtins.bindin( 20,m_stforecast2.p1,5);
    stmtins.bindin( 21,m_stforecast2.c2,5);
    stmtins.bindin( 22,m_stforecast2.c1,5);
    stmtins.bindin( 23,m_stforecast2.weather1,5);
    stmtins.bindin( 24,m_stforecast2.wind1,5);
    stmtins.bindin( 25,m_stforecast2.speed1,5);  
  }
  if (stmtupt.m_state==0)
  {
    stmtupt.connect(m_conn);
    stmtupt.prepare("update T_FORECAST set sx:1,wd=:2,csd=:3,wind=:4,speed=:5 where product=:6 and foretime=to_date(:7,'yyyy-mm-dd hh24:mi:ss') and obtid=:8 and sx=:9");
    stmtupt.bindin( 1,m_stforecast2.sx,3);
    stmtupt.bindin( 2,m_stforecast2.wd,5);
    stmtupt.bindin( 3,m_stforecast2.csd,5);
    stmtupt.bindin( 4,m_stforecast2.wind,5);
    stmtupt.bindin( 5,m_stforecast2.speed,5);
    stmtupt.bindin( 6,m_stforecast.product,5);
    stmtupt.bindin( 7,m_stforecast.foretime,19);
    stmtupt.bindin( 8,m_stforecast1.obtid,5);
    stmtupt.bindin( 9,m_stforecast2.sx,3);
  }
  if (stmtsel.execute() != 0)
  {
   //m_logfile->Write("%s,%s",m_stforecast.foretime,m_stforecast2.sx);
   invalidcount++; 
   m_logfile->Write("stmtsel.execute() failed.\n%s\n%s\n",stmtsel.m_sql,stmtsel.m_cda.message); 
   return stmtsel.m_cda.rc;
  }  
  iccount=0;
  stmtsel.next();
   // 必须是正确的数据才进行插入和查询
  if (c!=22){invalidcount++;}
  if(c==22){
  if (iccount>0) 
  {
    // 执行更新的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtupt.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("stmtupt.execute() failed.\n%s\n%s\n",stmtupt.m_sql,stmtupt.m_cda.message);
      return stmtupt.m_cda.rc;
    }
    updatecount++;
  }
  else
  {
    // 执行插入的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtins.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("\n%s,m_stforecast.foretime=%s,%s,%s,%lf,%s\n",m_stforecast.product,m_stforecast.foretime,m_stforecast1.obtid,m_stforecast2.sx,m_stforecast2.wd,m_stforecast2.csd);
      m_logfile->Write("stmtins.execute() failed.\n%s\n%s\n",stmtins.m_sql,stmtins.m_cda.message);
      return stmtins.m_cda.rc;
    }
    insertcount++;
  }
  }
  return 0;
}

7.酸雨数据:一二

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
//adid.cpp
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
CLogFile logfile;
CDir Dir;
// 处理数据文件
bool _adid();
connection conn;
void EXIT(int sig);

int main(int argc,char *argv[])
{
  if (argc!=5)
  {
    printf("\n本程序用于处理分区预警信号发布日志,并保存到数据库的T_ADID表中。\n");
    printf("/oracle/htidc/shqx/bin/adid 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\n");
    printf("例如:/oracle/htidc/shqx/bin/adid /oracle/data/shqx/sdata/adid /oracle/log/shqx/adid.log shqx/pwdidc@snorcl11g_128 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)
  {
     logfile.Write("开始扫描目录。\n");
    // 扫描数据文件存放的目录,只匹配"Z_*.DTB"
    if (Dir.OpenDir(argv[1],"Z_*.TXT",1000,true,true)==false)
    {
      logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]); sleep(atoi(argv[4])); continue;
    }
    // 逐个处理目录中的数据文件
    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);  
      // 处理数据文件
      if (_adid()==false) 
      {
        logfile.WriteEx("失败。\n"); break;
      }
    }
    // 断开与数据库的连接
    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);
}
     
// 处理数据文件
bool _adid()
{
  // 打开文件
  CFile File;
  if (File.Open(Dir.m_FullFileName,"r")==false)
  {
    logfile.Write("(File.Open(%s) failed.\n",Dir.m_FullFileName); return false;
  }
  CADID ADID(&conn,&logfile);
  // 读取文件中的每一行记录
  // 写入数据库的表中
  char strBuffer[301];
  while (true)
  {
    memset(strBuffer,0,sizeof(strBuffer));
    // 从文件中获取一行记录
    if (File.Fgets(strBuffer,300,true)==false) break;
    UpdateStr(strBuffer,"  "," ",true);  // 把内容中的两个空格替换成一个空格
    // logfile.Write("%s\n",strBuffer);    
    // 把用逗号分隔的记录拆分到结构体中
    if (ADID.SplitBuffer(strBuffer)==false) { logfile.Write("%s拆分失败\n",strBuffer); continue; }
    // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
    long rc=ADID.InsertTable();
    // 只要不是数据库session的错误,程序就继续。
    if ( (rc>=3113) && (rc<=3115) ) return false;
    if (rc != 0) { logfile.Write("插入失败%s\n",strBuffer); continue; }
  }
  // 提交事务
  conn.commit();
  // 关闭文件指针,并删除文件
  File.CloseAndRemove();
  logfile.WriteEx("成功(total=%d,insert=%d,update=%d,invalid=%d)。\n",ADID.totalcount,ADID.insertcount,ADID.updatecount,ADID.invalidcount);
  return true;
}
//_shqx.h
#ifndef _SHQX_H
#define _SHQX_H
#include "_public.h"
#include "_ooci.h"
struct st_adid
{
  char obtid[6];
  char lat[7];
  char lon[7];
  char height[7];
  char mode[2];
};
struct st_adid1
{
  char adidate[20];
  char astart[7];
  char aend[7];
  char r[6];
  char t[4];
  char ph1[5];
  char ph2[5];
  char ph3[5];
  char ph_av[5];
  char w[4];
  char s[4];
  char pheno[9];
};
#endif
//_shqx.cpp
#include "_shqx.h"
bool CADID::SplitBuffer(const char *strBuffer)
{
  totalcount++;
  CCmdStr CmdStr;
  CmdStr.SplitToCmd(strBuffer," ",true);
  c = CmdStr.CmdCount();
  if(CmdStr.CmdCount()==5)
  {
    memset(&m_stadid,0,sizeof(struct st_adid));
    CmdStr.GetValue(0,m_stadid.obtid,5); 
    CmdStr.GetValue(1,m_stadid.lat,5); 
    CmdStr.GetValue(2,m_stadid.lon,6); 
    CmdStr.GetValue(3,m_stadid.height,6);
    CmdStr.GetValue(4,m_stadid.mode,1);
  }
  if (CmdStr.CmdCount()==28)
  {
    memset(&m_stadid1,0,sizeof(struct st_adid1));
    CmdStr.GetValue(0,m_stadid1.adidate,16);
    AddTime(m_stadid1.adidate,m_stadid1.adidate,8*60*60,"yyyy-mm-dd hh24:mi:ss");
    CmdStr.GetValue(1,m_stadid1.astart,6); 
    CmdStr.GetValue(2,m_stadid1.aend,6); 
    CmdStr.GetValue(3,m_stadid1.r,5);
    CmdStr.GetValue(4,m_stadid1.t,3);
    CmdStr.GetValue(5,m_stadid1.ph1,4);
    CmdStr.GetValue(6,m_stadid1.ph2,4); 
    CmdStr.GetValue(7,m_stadid1.ph3,4);
    CmdStr.GetValue(8,m_stadid1.ph_av,4); 
    char strtemp[11];
    memset(strtemp,0,sizeof(strtemp));
    CmdStr.GetValue(22,strtemp,6);
    m_stadid1.w[0]=strtemp[0];
    m_stadid1.w[1]=strtemp[1];
    m_stadid1.w[2]=strtemp[2];
    m_stadid1.s[0]=strtemp[3];
    m_stadid1.s[1]=strtemp[4];
    m_stadid1.s[2]=strtemp[5];
    CmdStr.GetValue(26,m_stadid1.pheno,8);
  }
  return true;
}

long CADID::InsertTable()
{
  if (stmtsel.m_state==0)
  {
    stmtsel.connect(m_conn);
    stmtsel.prepare("select count(*) from T_ADID where obtid=:1 and adidate=to_date(:2,'yyyy-mm-dd hh24:mi:ss')");
    stmtsel.bindin(1,m_stadid.obtid,5);
    stmtsel.bindin(2,m_stadid1.adidate,19);
    stmtsel.bindout(1,&iccount);
  }
  if (stmtins.m_state==0)
  {
    stmtins.connect(m_conn);
    stmtins.prepare("insert into T_ADID values(:1,:2,:3,:4,:5,to_date(:6,'yyyy-mm-dd hh24:mi:ss'),:7,:8,:9,:10,:11,:12,:13,:14,:15,:16,:17,sysdate,SEQ_ADID.nextval)");
    stmtins.bindin( 1, m_stadid.obtid,5);
    stmtins.bindin( 2, m_stadid.lat,5);
    stmtins.bindin( 3, m_stadid.lon,6);
    stmtins.bindin( 4, m_stadid.height,6);
    stmtins.bindin( 5, m_stadid.mode,1);
    stmtins.bindin( 6, m_stadid1.adidate,19);
    stmtins.bindin( 7, m_stadid1.astart,6);
    stmtins.bindin( 8, m_stadid1.aend,6);
    stmtins.bindin( 9, m_stadid1.r,5);
    stmtins.bindin( 10,m_stadid1.t,3);
    stmtins.bindin( 11,m_stadid1.ph1,4);
    stmtins.bindin( 12,m_stadid1.ph2,4);
    stmtins.bindin( 13,m_stadid1.ph3,4);
    stmtins.bindin( 14,m_stadid1.ph_av,4);
    stmtins.bindin( 15,m_stadid1.w,3);
    stmtins.bindin( 16,m_stadid1.s,3);
    stmtins.bindin( 17,m_stadid1.pheno,8);
  
  }
  if (stmtupt.m_state==0)
  {
    stmtupt.connect(m_conn);
    stmtupt.prepare("update T_ADID set w=:1,pheno=:2 where obtid=:3 and adidate=to_date(:4,'yyyy-mm-dd hh24:mi:ss')");
    stmtupt.bindin(1,m_stadid1.w,3);
    stmtupt.bindin(2,m_stadid1.pheno,8);
    stmtupt.bindin(3,m_stadid.obtid,5);
    stmtupt.bindin(4,m_stadid1.adidate,19);
  }
  if (stmtsel.execute() != 0)
  {
    invalidcount++; 
    m_logfile->Write("stmtsel.execute() failed.\n%s\n%s\n",stmtsel.m_sql,stmtsel.m_cda.message); 
    return stmtsel.m_cda.rc;
  }  
  iccount=0;
  stmtsel.next();
   // 必须是正确的数据才进行插入和查询
  if (c!=28){invalidcount++;}
  if(c==28){
  if (iccount>0) 
  {
    // 执行更新的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtupt.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("stmtupt.execute() failed.\n%s\n%s\n",stmtupt.m_sql,stmtupt.m_cda.message);
      return stmtupt.m_cda.rc;
    }
    updatecount++;
  }
  else
  {
    // 执行插入的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtins.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("stmtins.execute() failed.\n%s\n%s\n",stmtins.m_sql,stmtins.m_cda.message);
      return stmtins.m_cda.rc;
    }
    insertcount++;
  }
  }
  return 0;
}

8.能见度数据:无分隔符

在这里插入图片描述

如上第一行为obtid(p5432),time(2018.....) ,第二行为vtime,vseeing,max_vseeing.....
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

//visibility.cpp
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
CLogFile logfile;
CDir Dir;
// 处理数据文件
bool _visibility();
connection conn;
void EXIT(int sig);
int main(int argc,char *argv[])
{
  if (argc!=5)
  {
    printf("\n本程序用于处理分区预警信号发布日志,并保存到数据库的T_VISIBILITY表中。\n");
    printf("/oracle/htidc/shqx/bin/visibility 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\n");
    printf("例如:/oracle/htidc/shqx/bin/visibility /oracle/data/shqx/sdata/visibility /oracle/log/shqx/visibility.log shqx/pwdidc@snorcl11g_128 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)
  {
     logfile.Write("开始扫描目录。\n");
    // 扫描数据文件存放的目录,只匹配"Z_*.DTB"
    if (Dir.OpenDir(argv[1],"P5*.TXT",1000,true,true)==false)
    {
      logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]); sleep(atoi(argv[4])); continue;
    }
    // 逐个处理目录中的数据文件
    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);  
      // 处理数据文件
      if (_visibility()==false) 
      {
        logfile.WriteEx("失败。\n"); break;
      }
    }
    // 断开与数据库的连接
    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);
}
     
// 处理数据文件
bool _visibility()
{
  // 打开文件
  CFile File;
  if (File.Open(Dir.m_FullFileName,"r")==false)
  {
    logfile.Write("(File.Open(%s) failed.\n",Dir.m_FullFileName); return false;
  }
  CVISIBILITY VISIBILITY(&conn,&logfile);
  // 读取文件中的每一行记录
  // 写入数据库的表中
  char strBuffer[301];
  while (true)
  {
    memset(strBuffer,0,sizeof(strBuffer));
    // 从文件中获取一行记录
    if (File.Fgets(strBuffer,300,true)==false) break;
    UpdateStr(strBuffer,"  "," ",true);  // 把内容中的两个空格替换成一个空格
    // logfile.Write("%s\n",strBuffer);    
    // 把用逗号分隔的记录拆分到结构体中
    if (VISIBILITY.SplitBuffer(strBuffer)==false) { logfile.Write("%s拆分失败\n",strBuffer); continue; }
    // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
    long rc=VISIBILITY.InsertTable();
    // 只要不是数据库session的错误,程序就继续。
    if ( (rc>=3113) && (rc<=3115) ) return false;
    if (rc != 0) { logfile.Write("插入失败%s\n",strBuffer); continue; }
  }
  // 提交事务
  conn.commit();
  // 关闭文件指针,并删除文件
  File.CloseAndRemove();
  logfile.WriteEx("成功(total=%d,insert=%d,update=%d,invalid=%d)。\n",VISIBILITY.totalcount,VISIBILITY.insertcount,VISIBILITY.updatecount,VISIBILITY.invalidcount);
  return true;
}
//_shqx.h
#ifndef _SHQX_H
#define _SHQX_H
#include "_public.h"
#include "_ooci.h
struct st_visbility
{
  char obtid[6];
  char time[20];
};
struct st_visbility1
{
  char vtime[20];
  char vseeing[7];
  char max_vseeing[7];
  char max_vseetime[20];
  char min_vseeing[7];
  char min_vseetime[20];
  char vseeing10[7];
  char max_vseeing10[7];
  char max_vseetime10[20];
  char min_vseeing10[7];
  char min_vseetime10[20];
  char qcc[11];
};
class CVISIBILITY
{
public:
  int totalcount,insertcount,updatecount,invalidcount;  // 记录总数据、插入数、更新数、无效记录数。
  int c;//个数
  struct st_visbility m_stvis;
  struct st_visbility1 m_stvis1;
  vector<struct st_typthon> vtypthon;   // 容器存放一个文件的全部记录

  CVISIBILITY(connection *conn,CLogFile *logfile);
 ~CVISIBILITY();
  void initdata();  // 数据初始化
  connection *m_conn;
  CLogFile   *m_logfile;
  int iccount;
  sqlstatement stmtsel,stmtins,stmtupt;
  // 把记录拆分到vsignallog容器中。
  bool SplitBuffer(const char *strBuffer);
  // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
  long InsertTable();
};
#endif
//_shqx.cpp
#include "_shqx.h"
CVISIBILITY::CVISIBILITY(connection *conn,CLogFile *logfile)
{
  initdata();
  m_conn=conn; m_logfile=logfile;
}
void CVISIBILITY::initdata()
{
  totalcount=insertcount=updatecount=invalidcount=0;
  m_conn=0; m_logfile=0;
  memset(&m_stvis,0,sizeof(struct st_visbility));
  memset(&m_stvis1,0,sizeof(struct st_visbility1));
}
CVISIBILITY::~CVISIBILITY()
{
}
bool CVISIBILITY::SplitBuffer(const char *strBuffer)
{
  totalcount++;
  CCmdStr CmdStr;
  CmdStr.SplitToCmd(strBuffer," ",true);
  c = CmdStr.CmdCount();
  if(CmdStr.CmdCount()==3)
  {
    memset(&m_stvis,0,sizeof(struct st_visbility));
    char strtemp[101];
    memset(strtemp,0,sizeof(strtemp));
    CmdStr.GetValue(0,strtemp); 
    STRNCPY(m_stvis.obtid,5,strtemp,5);
    STRNCPY(m_stvis.time,19,strtemp+5,8);

  }
  if (CmdStr.CmdCount()==1)
   {
     memset(&m_stvis1,0,sizeof(struct st_visbility1));
     char strtemp[101];
     memset(strtemp,0,sizeof(strtemp));
     CmdStr.GetValue(0,strtemp); 
     STRNCPY(m_stvis1.vtime,4,strtemp,4);
     STRNCPY(m_stvis1.vseeing,6,strtemp+4,6);
     STRNCPY(m_stvis1.max_vseeing,6,strtemp+10,6);
     STRNCPY(m_stvis1.max_vseetime,4,strtemp+16,4);
     STRNCPY(m_stvis1.min_vseeing,6,strtemp+20,6);
     STRNCPY(m_stvis1.min_vseetime,4,strtemp+26,4);
     STRNCPY(m_stvis1.vseeing10,6,strtemp+30,6);
     STRNCPY(m_stvis1.max_vseeing10,6,strtemp+36,6);
     STRNCPY(m_stvis1.max_vseetime10,4,strtemp+42,6);
     STRNCPY(m_stvis1.min_vseeing10,6,strtemp+48,6);
     STRNCPY(m_stvis1.min_vseetime10,4,strtemp+54,4);
     STRNCPY(m_stvis1.qcc,10,strtemp+58,10);
   }
   return true;
}

long CVISIBILITY::InsertTable()
{
  if (stmtsel.m_state==0)
  {
    stmtsel.connect(m_conn);
    stmtsel.prepare("select count(*) from T_VISIBILITY where obtid=:1 and time=to_date(:2,'yyyymmdd') and vtime=:3");
    stmtsel.bindin(1,m_stvis.obtid,5);
    stmtsel.bindin(2,m_stvis.time,19);
    stmtsel.bindin(3,m_stvis1.vtime,19);
    stmtsel.bindout(1,&iccount);
  }
  if (stmtins.m_state==0)
  {
    stmtins.connect(m_conn);
    stmtins.prepare("insert into T_VISIBILITY  values(:1,to_date(:2,'yyyymmdd'),:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,sysdate,SEQ_VISIBILITY.nextval)");
    stmtins.bindin( 1, m_stvis.obtid,5);
    stmtins.bindin( 2, m_stvis.time,19);
    stmtins.bindin( 3, m_stvis1.vtime,4);
    stmtins.bindin( 4, m_stvis1.vseeing,6);
    stmtins.bindin( 5, m_stvis1.max_vseeing,6);
    stmtins.bindin( 6, m_stvis1.max_vseetime,4);
    stmtins.bindin( 7, m_stvis1.min_vseeing,6);
    stmtins.bindin( 8, m_stvis1.min_vseetime,4);
    stmtins.bindin( 9, m_stvis1.vseeing10,6);
    stmtins.bindin( 10, m_stvis1.max_vseeing10,6);
    stmtins.bindin( 11, m_stvis1.max_vseetime10,4);
    stmtins.bindin( 12, m_stvis1.min_vseeing10,6);
    stmtins.bindin( 13, m_stvis1.min_vseetime10,4);
    stmtins.bindin( 14, m_stvis1.qcc,10);  
  }
  if (stmtupt.m_state==0)
  {
    stmtupt.connect(m_conn);
    stmtupt.prepare("update T_VISIBILITY set obtid=:1,vtime=:2 where obtid=:1 and vtime=:2");
    stmtupt.bindin(1,m_stvis.obtid,5);
    stmtupt.bindin(2,m_stvis1.vtime,19);
  }
  if (stmtsel.execute() != 0)
  {
    invalidcount++; 
    m_logfile->Write("stmtsel.execute() failed.\n%s\n%s\n",stmtsel.m_sql,stmtsel.m_cda.message); 
    return stmtsel.m_cda.rc;
  }  
  iccount=0;
  stmtsel.next();
   // 必须是正确的数据才进行插入和查询
  if (c!=1){invalidcount++;}
  if(c==1){
  if (iccount>0) 
  {
    // 执行更新的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtupt.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("stmtupt.execute() failed.\n%s\n%s\n",stmtupt.m_sql,stmtupt.m_cda.message);
      return stmtupt.m_cda.rc;
    }
    updatecount++;
  }
  else
  {
    // 执行插入的SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmtins.execute() != 0)
    {
      invalidcount++; 
      m_logfile->Write("stmtins.execute() failed.\n%s\n%s\n",stmtins.m_sql,stmtins.m_cda.message);
      return stmtins.m_cda.rc;
    }
    insertcount++;
  }
  }
  return 0;
}

9.区域自动站Z/S:风温湿压雨

在这里插入图片描述

如上之前生成的测试数据是全国的,下面是Z文件区域的,文件名不用管


在这里插入图片描述

在这里插入图片描述

第一行基本信息包含如下内容


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

下面是S文件二进制数据格式对应上面自动站Z文件
在这里插入图片描述

10.计算:gunzip,imp

如下利用需要算哪一天的日期,经纬度求出日出日落时间。如下站点代码和名称从全国气象站点参数表中取出。如下主键是站点代码,计算流程:首先看下下表计算时间是什么时候,今天已经算过的话就不需要再算了,今天没算过就从全国气象站点参数表中取参数再去计算,计算完后更新下表数据

在这里插入图片描述

如下是区域自动站z/s文件原始数据入库后导出的文件
在这里插入图片描述

如下expdat.dmp.gz解压后变为expdat.dmp
在这里插入图片描述

fromuser是指expdat.dmp从哪个用户导出来的
在这里插入图片描述

T_AREAOBTCODE表在下面数据计算生成其他数据集用不到,如下10天降雨量也多适合计算
在这里插入图片描述

分钟数据表和原始数据结构和数据一样,其他业务系统用分钟数据表
在这里插入图片描述

整点数据表只存放00分数据(如20点整点数据:第一条数据20点05分【此时是5分钟一周期,1分钟一周期就是01分】,最后一条数据21点00分,秒都为00)。小时雨量hourrf在一个整点累计,到下个整点时次05分清0【小时过了后数据记下来把水倒了重新接水】。极大风速等等都是本小时,一小时有很多条,整点数据表只要00分的一条,因为区域自动站数据分钟数据量大,一分钟观测一次有60条,有时候并不需要那么精确。如果一小时中00缺了就用55分
在这里插入图片描述

最新表只存放站点最新的一条数据,如下表的主键都有区站代码(假如:05分比:10分数据后到也取:10分)日数据表是站点一天(一天指大于昨天20时小于等于今天20时,如一天指第一条数据25号20:05,最后一条26号20:00)的统计数据,到整点表里取数据。气象平均值(02时,08时,14时,20时这四个定时次/4进行平均)
在这里插入图片描述

在这里插入图片描述

本小时累计雨量不够用,有时候会城市积涝即短时强降雨如30min30mm,想要过去30分钟降雨,如下只查出雨量数据
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

< tname >T_AREAOBTMIND</ tname >原始 , < train >T_GDOBTRAIND< /train > 雨量。T_GDAWSDAYD日,T_GDOBTREALD最新,T_GDOBTHOURD整点。如下select出后一定要排序,时间在前的一定先进去先算。查整点表11:00是否有数据,没有的话将分钟数据表里10:15数据插入,存在的话就更新,再把实际时间置为10:15。整点数据表里数据不断update,有05分数据时整点表里数据是05分,有10分更新为10分,最后更新为00分
在这里插入图片描述

如上第三条update要比较这个站点在最新表里数据时间,如果它时间比现在拿到的这条记录时间要早就更新。下面计算滑动雨量,分钟雨量就用当前这条记录减去上一时次记录得到,05分钟雨量和分钟雨量是同一个。10分钟滑动雨量最简单方法就是查雨量数据表过去10分钟记录雨量再加起来但性能不好,第二种方法是用一个sql把72小时雨量全部加载到内存的容器里排序
在这里插入图片描述

日数据表里昨天08时到今天08时最好的办法就是到整点数据表(整点表数据少查询效率高)里去查数据,最大10分钟滑动雨量到雨量数据表里查。日数据表不用等一天过完再统计,可十分钟统计一次

11.数据交换子系统:数据导出,数据文件推送

在这里插入图片描述

将导出后的数据进行数据推送,系统间数据交换采用ftp即公共协议比较多


在这里插入图片描述

以下在exptables.cpp中,一个表字段太多可选择导出一部分


在这里插入图片描述

如下增量导出还要按keyid排序,每次导出数据时会把最大的keyid保存起来,导出的是xml文件。假如要导出1万条记录,每1000条分拆到一个xml文件中,for_hb(环保),%d:1,2.....。where后1=1是为了格式和下面保持一致好传参数<andstr>。如下xml中的ddatetime是to char(...)的别名,keyid>:1就是>之前导过的keyid
在这里插入图片描述
// exptables.cpp
#include "_public.h"
#include "_ooci.h"
// 主程序的参数
struct st_arg
{
  char connstr[101];
  char charset[51];
  char tname[51];
  char cols[1001];
  char fieldname[1001];
  char fieldlen[501];
  int  exptype;
  char andstr[501];
  char bname[51];
  char ename[51];
  char taskname[51];
  char exppath[301];
  int  timetvl;
} starg;
CLogFile logfile;
connection conn;
// 本程序的业务流程主函数
bool _exptables();
void EXIT(int sig);

vector<string> vfieldname; // 存放拆分fieldname后的容器
vector<int>    vfieldlen;  // 存放拆分fieldlen后的容器
int maxfieldlen;           // 存放fieldlen的最大值
void SplitFields();        // 拆分fieldname和fieldlen

// 显示程序的帮助
void _help(char *argv[]);
long maxkeyid;   // 已导出数据的最大的keyid
bool LoadMaxKeyid(); // 从系统参数T_SYSARG表中加载已导出数据的最大的keyid
bool UptMaxKeyid();  // 更新系统参数T_SYSARG表中已导出数据的最大的keyid  
// 把xml解析到参数starg结构中
bool _xmltoarg(char *strxmlbuffer);

int main(int argc,char *argv[])
{
  if (argc!=3) { _help(argv); return -1; }
  // 关闭全部的信号和输入输出
  CloseIOAndSignal();
  // 处理程序退出的信号
  signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[1],"a+")==false)
  {
    printf("打开日志文件失败(%s)。\n",argv[1]); return -1;
  }
  // 把xml解析到参数starg结构中
  if (_xmltoarg(argv[2])==false) return -1;
  while (true)
  {
    // 连接数据库 //放while (true)外面连耗资源
    if (conn.connecttodb(starg.connstr,starg.charset) != 0)
    {
      logfile.Write("connect database %s failed.\n",starg.connstr); sleep(starg.timetvl); continue;
    }
    // logfile.Write("export table %s.\n",starg.tname);
    if (_exptables() == false) logfile.Write("export tables failed.\n"); //导出数据的主函数
    conn.disconnect();   // 断开与数据库的连接
    sleep(starg.timetvl);
  }
  return 0;
}
void EXIT(int sig)
{
  logfile.Write("程序退出,sig=%d\n\n",sig);
  exit(0);
}

void _help(char *argv[])
{
  printf("\n");
  printf("Using:/htidc/public/bin/exptables logfilename xmlbuffer\n\n");

  printf("增量导出示例:\n");
  printf("/htidc/public/bin/exptables /log/shqx/exptables_surfdata_for_hb.log \"<connstr>shqx/pwdidc@snorcl11g_198</connstr><charset>Simplified Chinese_China.ZHS16GBK</charset><tname>T_SURFDATA</tname><cols>obtid,to_char(ddatetime,'yyyymmddhh24miss'),t,p,u,wd,wf,r,vis</cols><fieldname>obtid,ddatetime,t,p,u,wd,wf,r,vis</fieldname><fieldlen>5,14,8,8,8,8,8,8,8</fieldlen><exptype>1</exptype><andstr> and obtid in ('59293','50745')</andstr><bname>SURFDATA_</bname><ename>_for_hb</ename><taskname>SURFDATA_FOR_HB</taskname><exppath>/data/shqx/exp/tohb</exppath><timetvl>30</timetvl>\"\n\n");
  printf("全量导出示例:\n");
  printf("/htidc/public/bin/exptables /log/shqx/exptables_obtcode_for_hb.log \"<connstr>shqx/pwdidc@snorcl11g_198</connstr><charset>Simplified Chinese_China.ZHS16GBK</charset><tname>T_OBTCODE</tname><cols>obtid,obtname,provname,lat,lon,height</cols><fieldname>obtid,obtname,provname,lat,lon,height</fieldname><fieldlen>5,30,30,8,8,8</fieldlen><exptype>2</exptype><andstr> and rsts=1 and obtid in ('59293','50745')</andstr><bname>OBTCODE_</bname><ename>_for_hb</ename><exppath>/data/shqx/exp/tohb</exppath><timetvl>300</timetvl>\"\n\n");

  printf("本程序是数据中心的公共功能模块,从数据库的表中导出数据生成xml文件,用于数据交换。\n");
  printf("logfilename是本程序运行的日志文件。\n");
  printf("xmlbuffer为文件传输的参数,如下:\n");
  printf("数据库的连接参数 <connstr>shqx/pwdidc@snorcl11g_198</connstr>\n");
  printf("数据库的字符集 <charset>Simplified Chinese_China.ZHS16GBK</charset> 这个参数要与数据源数据库保持>一致,否则会出现中文乱码的情况。\n");
  printf("待导出数据的表名 <tname>T_SURFDATA</tname>\n");
  printf("需要导出字段的列表 <cols>obtid,to_char(ddatetime,'yyyymmddhh24miss'),t,p,u,wd,wf,r,vis</cols> 可以采用函数。\n");
  printf("导出字段的别名列表 <fieldname>obtid,ddatetime,t,p,u,wd,wf,r,vis</fieldname> 必须与cols一一对应。\n");
  printf("导出字段的长度列表 <fieldlen>5,14,8,8,8,8,8,8,8</fieldlen> 必须与cols一一对应。\n");
  printf("导出数据的方式 <exptype>1</exptype> 1-增量导出;2-全量导出,如果是增量导出,要求表一定要有keyid字段。\n");
  printf("导出数据的附加条件 <andstr> and obtid in ('59293','50745')</andstr> 注意,关键字and不能少。\n");
  printf("导出文件的命名的前部分 <bname>SURFDATA_</bname>\n");
  printf("导出文件的命名的后部分 <ename>_for_hb</ename>\n");
  printf("导出任务的命名 <taskname>SURFDATA_FOR_HB</taskname> 当exptype=1时该参数有效。\n");
  printf("导出文件存放的目录 <exppath>/data/shqx/exp/tohb</exppath>\n");
  printf("导出数据的时间间隔 <timetvl>30</timetvl> 单位:秒,建议大于10。\n");
  printf("以上参数,除了taskname和andstr,其它字段都不允许为空。\n\n\n");
}

bool _xmltoarg(char *strxmlbuffer)
{
  memset(&starg,0,sizeof(struct st_arg));
  GetXMLBuffer(strxmlbuffer,"connstr",starg.connstr);
  if (strlen(starg.connstr)==0) { logfile.Write("connstr is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"charset",starg.charset);
  if (strlen(starg.charset)==0) { logfile.Write("charset is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"tname",starg.tname);
  if (strlen(starg.tname)==0) { logfile.Write("tname is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"cols",starg.cols);
  if (strlen(starg.cols)==0) { logfile.Write("cols is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"fieldname",starg.fieldname);
  if (strlen(starg.fieldname)==0) { logfile.Write("fieldname is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"fieldlen",starg.fieldlen);
  if (strlen(starg.fieldlen)==0) { logfile.Write("fieldlen is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"exptype",&starg.exptype);
  if ( (starg.exptype!=1) && (starg.exptype!=2) ) { logfile.Write("exptype is not in (1,2).\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"andstr",starg.andstr);
  if (strlen(starg.andstr)==0) { logfile.Write("andstr is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"bname",starg.bname);
  if (strlen(starg.bname)==0) { logfile.Write("bname is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"ename",starg.ename);
  if (strlen(starg.ename)==0) { logfile.Write("ename is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"taskname",starg.taskname);
  if ( (starg.exptype==1) && (strlen(starg.taskname)==0) ) { logfile.Write("taskname is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"exppath",starg.exppath);
  if (strlen(starg.exppath)==0) { logfile.Write("exppath is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"timetvl",&starg.timetvl);
  if (starg.timetvl==0) { logfile.Write("timetvl is null.\n"); return false; }
  // 拆分fieldname和fieldlen
  SplitFields();
  // 判断fieldname和fieldlen中元素的个数一定要相同
  if (vfieldname.size() != vfieldlen.size() ) { logfile.Write("fieldname和fieldlen的元素个数不同。.\n"); return false; }
  return true;
}

////////////////////////////////////////////////1.本程序的业务流程主函数
bool _exptables()
{
  // 从系统参数T_SYSARG表中加载已导出数据的最大的keyid
  if (LoadMaxKeyid()==false) { logfile.Write("LoadMaxKeyid() failed.\n"); return false; }
 
  // 生成导出数据的SQL语句
  char strsql[4096]; 
  char fieldvalue[vfieldname.size()][maxfieldlen+1]; // 输出变量定义为一个二维数组
  //第一维vfieldname.size()字段个数(限制fieldvalue外个数),第二维maxfieldlen+1字段长度(限制fieldvalue内个数),+1是最后一个空字符结尾符
  //导出数据的结果不管是字符串,整数还是浮点数都用字符串存放
 
  memset(strsql,0,sizeof(strsql));
  if (starg.exptype==1)  //增量导出, order by keyid排完序后数据好导入
    sprintf(strsql,"select %s,keyid from %s where 1=1 and keyid>%ld %s order by keyid",starg.cols,starg.tname,maxkeyid,starg.andstr);
  else //全量导出不需要keyid
    sprintf(strsql,"select %s from %s where 1=1 %s",starg.cols,starg.tname,starg.andstr);
 
  sqlstatement stmt(&conn);
  stmt.prepare(strsql);  
  for (int ii=0;ii<vfieldname.size();ii++)
  {
    stmt.bindout(ii+1,fieldvalue[ii],vfieldlen[ii]); //绑定变量从1开始算
  }
  // 如果是增量导出,还要绑定keyid字段
  if (starg.exptype==1) stmt.bindout(vfieldname.size()+1,&maxkeyid);    
  // 执行导出数据的SQL
  if (stmt.execute() != 0)
  {
    logfile.Write("select %s failed.\n%s\n%s\n",starg.tname,stmt.m_cda.message,stmt.m_sql); return false;
  }
  
  int  iFileSeq=1;   // 待生成文件的序号,临时变量,文件名不会重复了
  char strFileName[301],strLocalTime[21];
  CFile File;
  while (true)
  {   // 如果在循环外面打开文件,stmt.next若是没记录又要删除文件
    memset(fieldvalue,0,sizeof(fieldvalue));   
    if (stmt.next() !=0) break;
    // 把数据写入文件
    if (File.IsOpened()==false)
    {
      memset(strLocalTime,0,sizeof(strLocalTime));
      LocalTime(strLocalTime,"yyyymmddhh24miss");
      memset(strFileName,0,sizeof(strFileName));
      sprintf(strFileName,"%s/%s%s%s_%d.xml",starg.exppath,starg.bname,strLocalTime,starg.ename,iFileSeq++);
      if (File.OpenForRename(strFileName,"w")==false)
      {
        logfile.Write("File.OpenForRename(%s) failed.\n",strFileName); return false;
      }
      File.Fprintf("<data>\n");
    }
    for (int ii=0;ii<vfieldname.size();ii++)
    { //数据一个字段一个字段写入xml文件中
      File.Fprintf("<%s>%s</%s>",vfieldname[ii].c_str(),fieldvalue[ii],vfieldname[ii].c_str());
    }
    File.Fprintf("<endl/>\n");
    
//////////////////////////////////////////////////1.1有1000条记录写入一个文件完成
    if (stmt.m_cda.rpc%1000==0)  //每写入1000行关闭文件
    {
      File.Fprintf("</data>\n");
      if (File.CloseAndRename()==false)
      {
        logfile.Write("File.CloseAndRename(%s) failed.\n",strFileName); return false;
      }
      // 更新系统参数T_SYSARG表中已导出数据的最大的keyid
      if (UptMaxKeyid()==false) { logfile.Write("UptMaxKeyid() failed.\n"); return false; }
      logfile.Write("create file %s ok.\n",strFileName);
    }
  }

///////////////////////////////////////////1.2不够1000条的写入一个文件
  if (File.IsOpened()==true)
  {
    File.Fprintf("</data>\n");
    if (File.CloseAndRename()==false)
    {
      logfile.Write("File.CloseAndRename(%s) failed.\n",strFileName); return false;
    }
    // 更新系统参数T_SYSARG表中已导出数据的最大的keyid
    if (UptMaxKeyid()==false) { logfile.Write("UptMaxKeyid() failed.\n"); return false; }
    logfile.Write("create file %s ok.\n",strFileName);
  }
  if (stmt.m_cda.rpc>0) logfile.Write("本次导出了%d条记录。\n",stmt.m_cda.rpc);
  return true;
}

/////////////////////////////////////////////2.拆分fieldname和fieldlen
void SplitFields()
{
  vfieldname.clear(); vfieldlen.clear(); maxfieldlen=0;  
  CCmdStr CmdStr;
  CmdStr.SplitToCmd(starg.fieldname,",");
  vfieldname.swap(CmdStr.m_vCmdStr);
  int ifieldlen=0;
  CmdStr.SplitToCmd(starg.fieldlen,",");
  for (int ii=0;ii<CmdStr.CmdCount();ii++)
  {  
    CmdStr.GetValue(ii,&ifieldlen); //maxfieldlen一开始为0
    if (ifieldlen>maxfieldlen) maxfieldlen=ifieldlen; //得到fieldlen的最大值maxfieldlen
    vfieldlen.push_back(ifieldlen);
  }
}

/////////////////////////////////////3.从系统参数T_SYSARG表中加载已导出数据的最大的keyid
bool LoadMaxKeyid() //实现增量采集必须把每次导出数据的keyid保存起来,所以采用一个T_SYSARG参数表
{   //taskname作为参数代码argcode
  if (starg.exptype!=1) return true; //只有增量导出才需要加载/更新系统参数表
  sqlstatement stmt(&conn);
  stmt.prepare("select argvalue from T_SYSARG where argcode=:1");
  stmt.bindin(1,starg.taskname,50);
  stmt.bindout(1,&maxkeyid);
  if (stmt.execute() != 0)
  {
    logfile.Write("select T_SYSARG failed.\n%s\n%s\n",stmt.m_cda.message,stmt.m_sql); return false;
  }
  // 如果记录不存在,插入一新记录。
  if (stmt.next() != 0)
  { //一直只有一条记录:SURFDATA_FOR_HB,SURFDATA_FOR_HB,0
    stmt.prepare("insert into T_SYSARG(argcode,argname,argvalue) values(:1,:2,0)");
    stmt.bindin(1,starg.taskname,50);
    stmt.bindin(2,starg.taskname,50);
    stmt.execute();
    conn.commit();
  }
  // logfile.Write("maxkeyid=%d\n",maxkeyid);
  return true;
}

////////////////////////////////4.更新系统参数T_SYSARG表中已导出数据的最大的keyid
bool UptMaxKeyid() //导出前加载,导出后更新
{
  if (starg.exptype!=1) return true;
  sqlstatement stmt(&conn);
  stmt.prepare("update T_SYSARG set argvalue=:1 where argcode=:2");
  stmt.bindin(1,&maxkeyid);
  stmt.bindin(2,starg.taskname,50);
  if (stmt.execute() != 0)
  {
    logfile.Write("select T_SYSARG failed.\n%s\n%s\n",stmt.m_cda.message,stmt.m_sql); return false;
  }
  conn.commit();
  return true;
}

下面为全量导出站点参数

在这里插入图片描述

在这里插入图片描述

vi ...1.xml,只导出了2条记录一个文件
在这里插入图片描述

下面为增量导出地面观测数据
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

//ftpputfiles.cpp系统间传输
#include "_public.h"
#include "_ftp.h"
struct st_arg
{
  char host[51];
  int  mode;
  char username[31];
  char password[31];
  char localpath[301];
  char remotepath[301];
  char matchname[301];
  int  ptype;
  char localpathbak[301];
  char okfilename[301];
  int  timetvl;
} starg;
Cftp ftp;
CLogFile logfile;
// 本程序的业务流程主函数
bool _ftpputfiles();
vector<struct st_fileinfo> vlistfile,vlistfile1;
vector<struct st_fileinfo> vokfilename,vokfilename1;
// 把localpath目录下的文件加载到vlistfile容器中
bool LoadListFile();
// 把okfilename文件内容加载到vokfilename容器中
bool LoadOKFileName();
// 把vlistfile容器中的文件与vokfilename容器中文件对比,得到两个容器
// 一、在vlistfile中存在,并已经发送成功的文件vokfilename1
// 二、在vlistfile中存在,新文件或需要重新发送的文件vlistfile1
bool CompVector();
// 把vokfilename1容器中的内容先写入okfilename文件中,覆盖之前的旧okfilename文件
bool WriteToOKFileName();
// 如果ptype==1,把发送成功的文件记录追加到okfilename文件中
bool AppendToOKFileName(struct st_fileinfo *stfileinfo);
void EXIT(int sig);
// 显示程序的帮助
void _help(char *argv[]);  
// 把xml解析到参数starg结构中
bool _xmltoarg(char *strxmlbuffer);

int main(int argc,char *argv[])
{
  if (argc!=3) { _help(argv); return -1; }
  // 关闭全部的信号和输入输出
  CloseIOAndSignal();
  // 处理程序退出的信号
  signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[1],"a+")==false)
  {
    printf("打开日志文件失败(%s)。\n",argv[1]); return -1;
  }
  // 把xml解析到参数starg结构中
  if (_xmltoarg(argv[2])==false) return -1;
  while (true)
  {
    if (ftp.login(starg.host,starg.username,starg.password,starg.mode)==false)
    {
      logfile.Write("ftp.login(%s,%s,%s) failed.\n",starg.host,starg.username,starg.password); sleep(10); continue;
    }
    // logfile.Write("ftp.login ok.\n");  
    _ftpputfiles();
    ftp.logout();
    sleep(starg.timetvl);
  }
  return 0;
}
void EXIT(int sig)
{
  logfile.Write("程序退出,sig=%d\n\n",sig);
  exit(0);
}

////////////////////////////////////////////1.本程序的业务流程主函数
bool _ftpputfiles()
{
  // 创建远程服务器上的目录,不关心返回值。能成功就创建,没权限不能成功创建就算了
  ftp.mkdir(starg.remotepath);
  // 把localpath目录下的文件加载到vlistfile容器中
  if (LoadListFile()==false) 
  {
    logfile.Write("LoadListFile() failed.\n"); return false;
  }
  if (starg.ptype==1)
  {
    // 加载okfilename文件中的内容到容器vokfilename中
    LoadOKFileName();
    // 把vlistfile容器中的文件与vokfilename容器中文件对比,得到两个容器
    // 一、在vlistfile中存在,并已经发送成功的文件vokfilename1
    // 二、在vlistfile中存在,新文件或需要重新发送的文件vlistfile1
    CompVector();
    // 把vokfilename1容器中的内容先写入okfilename文件中,覆盖之前的旧okfilename文件
    WriteToOKFileName();    
    // 把vlistfile1容器中的内容复制到vlistfile容器中
    vlistfile.clear(); vlistfile.swap(vlistfile1);
  }

////////////////////////////1.1把客户端的新文件或已改动过后的文件发送给服务端
  for (int ii=0;ii<vlistfile.size();ii++)
  {
    char strremotefilename[301],strlocalfilename[301];
    SNPRINTF(strlocalfilename,300,"%s/%s",starg.localpath,vlistfile[ii].filename);
    SNPRINTF(strremotefilename,300,"%s/%s",starg.remotepath,vlistfile[ii].filename);
    logfile.Write("put %s ...",strlocalfilename);
    // 发送文件
    if (ftp.put(strlocalfilename,strremotefilename,true)==false) 
    {
      logfile.WriteEx("failed.\n"); break;
    }
    logfile.WriteEx("ok.\n");    
    // 删除文件
    if (starg.ptype==2) REMOVE(strlocalfilename);
    // 转存到备份目录
    if (starg.ptype==3)
    {
      char strfilenamebak[301];
      memset(strfilenamebak,0,sizeof(strfilenamebak));
      sprintf(strfilenamebak,"%s/%s",starg.localpathbak,vlistfile[ii].filename);
      if (RENAME(strlocalfilename,strfilenamebak)==false)
      {
        logfile.Write("RENAME %s to %s failed.\n",strlocalfilename,strfilenamebak); return false;
      }
    }  
    // 如果ptype==1,把发送成功的文件记录追加到okfilename文件中
    if (starg.ptype==1) AppendToOKFileName(&vlistfile[ii]);
  } 
  return true;
}

//////////////////////////////2.把localpath目录下的文件加载到vlistfile容器中
bool LoadListFile()
{
  vlistfile.clear();
  CDir Dir;
  // 不包括子目录
  // 注意,如果目录下的总文件数超过50000,增量发送文件功能将有问题
  if (Dir.OpenDir(starg.localpath,starg.matchname,50000,false,false)==false)
  {
    logfile.Write("Dir.OpenDir(%s) 失败。\n",starg.localpath); return false;
  }
  struct st_fileinfo stfileinfo;
  while (true)
  {
    memset(&stfileinfo,0,sizeof(struct st_fileinfo));
    if (Dir.ReadDir()==false) break;
    strcpy(stfileinfo.filename,Dir.m_FileName);  // 文件名,不包括目录名
    strcpy(stfileinfo.mtime,Dir.m_ModifyTime);
    stfileinfo.filesize=Dir.m_FileSize;
    vlistfile.push_back(stfileinfo);
    // logfile.Write("vlistfile filename=%s,mtime=%s\n",stfileinfo.filename,stfileinfo.mtime);
  }
  return true;
}

////////////////////////////3.把okfilename文件内容加载到vokfilename容器中
bool LoadOKFileName()
{
  vokfilename.clear();
  CFile File;
  // 注意:如果程序是第一次发送,okfilename是不存在的,并不是错误,所以也返回true。
  if (File.Open(starg.okfilename,"r") == false) return true;
  struct st_fileinfo stfileinfo;
  char strbuffer[301];
  while (true)
  {
    memset(&stfileinfo,0,sizeof(struct st_fileinfo));
    if (File.Fgets(strbuffer,300,true)==false) break;
    GetXMLBuffer(strbuffer,"filename",stfileinfo.filename,300);
    GetXMLBuffer(strbuffer,"mtime",stfileinfo.mtime,20);
    vokfilename.push_back(stfileinfo);
    // logfile.Write("vokfilename filename=%s,mtime=%s\n",stfileinfo.filename,stfileinfo.mtime);
  }
  return true;
}

////////////////////////4.把vlistfile容器中的文件与vokfilename容器中文件对比,得到两个容器
// 一、在vlistfile中存在,并已经发送成功的文件vokfilename1
// 二、在vlistfile中存在,新文件或需要重新发送的文件vlistfile1
bool CompVector()
{
  vokfilename1.clear();  vlistfile1.clear();
  for (int ii=0;ii<vlistfile.size();ii++)
  {
    int jj=0;
    for (jj=0;jj<vokfilename.size();jj++)
    {
      if ( (strcmp(vlistfile[ii].filename,vokfilename[jj].filename)==0) &&
           (strcmp(vlistfile[ii].mtime,vokfilename[jj].mtime)==0) )
      {
        vokfilename1.push_back(vlistfile[ii]); break;
      }
    }
    if (jj==vokfilename.size())
    {
      vlistfile1.push_back(vlistfile[ii]);
    }
  }
  /*
  for (int ii=0;ii<vokfilename1.size();ii++)
  {
    logfile.Write("vokfilename1 filename=%s,mtime=%s\n",vokfilename1[ii].filename,vokfilename1[ii].mtime);
  }

  for (int ii=0;ii<vlistfile1.size();ii++)
  {
    logfile.Write("vlistfile1 filename=%s,mtime=%s\n",vlistfile1[ii].filename,vlistfile1[ii].mtime);
  }
  */
  return true;
}

////////////////////////////5.把vokfilename1容器中的内容先写入okfilename文件中,覆盖之前的旧okfilename文件
bool WriteToOKFileName()
{
  CFile File;
  // 注意,打开文件不要采用缓冲机制
  if (File.Open(starg.okfilename,"w",false) == false)
  {
    logfile.Write("File.Open(%s) failed.\n",starg.okfilename); return false;
  }
  for (int ii=0;ii<vokfilename1.size();ii++)
  {
    File.Fprintf("<filename>%s</filename><mtime>%s</mtime>\n",vokfilename1[ii].filename,vokfilename1[ii].mtime);
  }
  return true;
}

//////////////////////////////6.如果ptype==1,把发送成功的文件记录追加到okfilename文件中
bool AppendToOKFileName(struct st_fileinfo *stfileinfo)
{
  CFile File;
  // 注意,打开文件不要采用缓冲机制
  if (File.Open(starg.okfilename,"a",false) == false)
  {
    logfile.Write("File.Open(%s) failed.\n",starg.okfilename); return false;
  }
  File.Fprintf("<filename>%s</filename><mtime>%s</mtime>\n",stfileinfo->filename,stfileinfo->mtime);
  return true;
}

/////////////////////////////////////7.显示程序的帮助
void _help(char *argv[])
{
  printf("\n");
  printf("Using:/htidc/public/bin/ftpputfiles logfilename xmlbuffer\n\n");
  printf("Sample:/htidc/public/bin/ftpputfiles /log/shqx/ftpputfiles_surfdata.log \"<host>172.16.0.15:21</host><port>21</port><mode>1</mode><username>oracle</username><password>te.st1234TES@T</password><localpath>/data/shqx/ftp/surfdata</localpath><remotepath>/data/shqx/sdata/surfdata</remotepath><matchname>SURF_*.TXT,*.DAT</matchname><ptype>1</ptype><localpathbak></localpathbak><okfilename>/data/shqx/ftplist/ftpputfiles_surfdata.xml</okfilename><timetvl>30</timetvl>\"\n\n\n");
  printf("本程序是数据中心的公共功能模块,用于把本地目录中的文件发送到远程的FTP服务器。\n");
  printf("logfilename是本程序运行的日志文件。\n");
  printf("xmlbuffer为文件传输的参数,如下:\n");
  printf("<host>118.89.50.198:21</host> 远程服务器的IP和端口。\n");
  printf("<mode>1</mode> 传输模式,1-被动模式,2-主动模式,缺省采用被模式。\n");
  printf("<username>wucz</username> 远程服务器FTP的用户名。\n");
  printf("<password>test1234TEST</password> 远程服务器FTP的密码。\n");
  printf("<localpath>/tmp/ftpput</localpath> 本地文件存放的目录。\n");
  printf("<remotepath>/tmp/gzrad</remotepath> 远程服务器存放文件的目录。\n");
  printf("<matchname>*.GIF</matchname> 待发送文件匹配的文件名,采用大写匹配,"\
         "不匹配的文件不会被发送,本字段尽可能设置精确,不允许用*匹配全部的文件。\n");
  printf("<ptype>1</ptype> 文件发送成功后,本地文件的处理方式:1-什么也不做;2-删除;3-备份,如果为3,还要指定备份的目录。\n");
  printf("<localpathbak>/tmp/gzradbak</localpathbak> 文件发送成功后,本地文件的备份目录,此参数只有当ptype=3时才有效。\n");
  printf("<okfilename>/oracle/qxidc/list/ftpgetfiles_surfdata.xml</okfilename> 已采集成功文件名清单,此参数只有当ptype=1时有效。\n");
  printf("<timetvl>30</timetvl> 发送时间间隔,单位:秒,建议大于10。\n\n");
}

bool _xmltoarg(char *strxmlbuffer)
{
  memset(&starg,0,sizeof(struct st_arg));
  GetXMLBuffer(strxmlbuffer,"host",starg.host);
  if (strlen(starg.host)==0) { logfile.Write("host is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"mode",&starg.mode);
  if ( (starg.mode!=1) && (starg.mode!=2) ) starg.mode=1;
  GetXMLBuffer(strxmlbuffer,"username",starg.username);
  if (strlen(starg.username)==0) { logfile.Write("username is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"password",starg.password);
  if (strlen(starg.password)==0) { logfile.Write("password is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"localpath",starg.localpath);
  if (strlen(starg.localpath)==0) { logfile.Write("localpath is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"remotepath",starg.remotepath);
  if (strlen(starg.remotepath)==0) { logfile.Write("remotepath is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"matchname",starg.matchname);
  if (strlen(starg.matchname)==0) { logfile.Write("matchname is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"ptype",&starg.ptype);
  if ( (starg.ptype!=1) && (starg.ptype!=2) && (starg.ptype!=3) ){ logfile.Write("ptype is error.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"localpathbak",starg.localpathbak);
  if ((starg.ptype==3) && (strlen(starg.localpathbak)==0)) { logfile.Write("localpathbak is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"okfilename",starg.okfilename);
  if ((starg.ptype==1) && (strlen(starg.okfilename)==0)) { logfile.Write("okfilename is null.\n"); return false; }
  GetXMLBuffer(strxmlbuffer,"timetvl",&starg.timetvl);
  if (starg.timetvl==0) { logfile.Write("timetvl is null.\n"); return false; }
  return true;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345