文章目录

  • 1.txt/xml文件入表/自身调度:结构体内容
  • 2.分区/表空间/网络/主键/错误优化:chown -R 用户
  • 3.历史文件/表数据清理:生成测试数据后去采集,采集后未删除文件,因为数据不只一个系统用
  • 4.站点参数建表入表/PowerDesigner/主外键:g/./s//./g,多表查询

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

// makefile
#oracle头文件路径
ORAINCL = -I$(ORACLE_HOME)/rdbms/public# oracle库文件路径
ORALIB =  -L$(ORACLE_HOME)/lib -L.# oracle的oci库
ORALIBS = -lclntshCC=g++
CFLAGS = -g -Wno-write-strings -Wno-unused-variableall:crtsurfdata libftp.a demo18 ftpgetfile psurfdatalibftp.a:ftplib.cgcc -c -o libftp.a ftplib.cdemo18:demo18.cpp _ftp.h _ftp.cpp libftp.ag++ $(CFLAGS) -o demo18 demo18.cpp _public.cpp _ftp.cpp libftp.aftpgetfile:ftpgetfile.cpp _ftp.h _ftp.cpp libftp.a$(CC) $(CFLAGS) -o ftpgetfile ftpgetfile.cpp _public.cpp _ftp.cpp libftp.acp ftpgetfile ../bin/.crtsurfdata:crtsurfdata.cpp _public.h _public.cpp$(CC) $(CFLAGS) -o crtsurfdata crtsurfdata.cpp _public.cppcp crtsurfdata ../bin/.psurfdata:psurfdata.cpp _public.h _public.cppg++ $(CFLAGS) -o psurfdata psurfdata.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _public.cpp _ooci.cppcp 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/sint  r;              // 降雨量:0.1mmint  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.nextvalstmtins.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.3CmdStr.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.obtidCmdStr.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/sCmdStr.GetValue(7,&dtmp); stsurfdata.r=(int)(dtmp*10);   // 降雨量:0.1mmCmdStr.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(atoi(argv[4]));}return 0;
}
void EXIT(int sig)
{logfile.Write("程序退出,sig=%d\n\n",sig);exit(0);
}//111111111111111111111111111111111111111111111111.处理入库
bool _psurfdata()
{CFile File;if (File.Open(Dir.m_FullFileName,"r")==false){logfile.Write("(File.Open(%s) failed.\n",Dir.m_FullFileName); return false;}//1111111111111111111111111111读取文件中的每一行记录,写入数据库的表中CSURFDATA SURFDATA(&conn,&logfile); //上行给m_conn和m_logfile两个指针成员变量赋值初始化也可写成如下两行://SURFDATA.m_conn=&conn;  //con是对象也是变量//SURFDATA.m_logfile=&logfile;char strBuffer[301];                                           while (true){memset(strBuffer,0,sizeof(strBuffer));if (File.Fgets(strBuffer,300,true)==false) break; //从文件中获取一行记录   if (SURFDATA.SplitBuffer(strBuffer)==false) { logfile.Write("%s\n",strBuffer); continue; }// 把用逗号分隔的记录拆分到结构体中long rc=SURFDATA.InsertTable(); //把结构体中的数据更新到T_SURFDATA表中,因为不知道返回哪个sql,所以用long rc =if ( (rc>=3113) && (rc<=3115) ) return false; //只要不是数据库session的错误,程序就继续。if (rc != 0) { logfile.Write("%s\n",strBuffer); continue; }}conn.commit(); //提交事务File.CloseAndRemove(); //关闭文件指针,并删除文件logfile.WriteEx("成功(total=%d,insert=%d,update=%d,invalid=%d)。\n",SURFDATA.totalcount,SURFDATA.insertcount,SURFDATA.updatecount,SURFDATA.invalidcount);return true;
}
//psurfdata1.cpp本程序只支持xml文件入库已封装成类,有keyid等字段。
//表加字段,结构体不用,在sqlplus中输入一行创建序列命令,stcode.ini不要最后留空行
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
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("与psurfdata.cpp不同,本程序只支持xml格式。\n");printf("/htidc/shqx/bin/psurfdata1 数据文件存放的目录 日志文件名 数据库连接参数 程序运行时间间隔\n");printf("例如:/htidc/shqx/bin/psurfdata1 /data/shqx/sdata/surfdata /log/shqx/psurfdata1.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){
//1111111111111111111111111111111111111111111.扫描数据文件存放的目录,匹配"SURF_ZH_*.xml"// logfile.Write("开始扫描目录。\n");if (Dir.OpenDir(argv[1],"SURF_ZH_*.xml",1000,true,true)==false){logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]); sleep(atoi(argv[4])); continue;}//111111111111111111111111111111111111111111111.逐个处理目录中的数据文件while (true){if (Dir.ReadDir()==false) break;//111111111111111111111111111111111111111111111.连接数据库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);//111111111111111111111111111111111111111111111.处理入库if (_psurfdata()==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);
}//111111111111111111111111111111111111111111111.处理入库
bool _psurfdata()
{CFile File;if (File.Open(Dir.m_FullFileName,"r")==false){logfile.Write("(File.Open(%s) failed.\n",Dir.m_FullFileName); return false;}CSURFDATA SURFDATA(&conn,&logfile);char strBuffer[301];while (true){memset(strBuffer,0,sizeof(strBuffer));if (File.FFGETS(strBuffer,300,"<endl/>")==false) break;// logfile.Write("str=%s=\n",strBuffer);// logfile.Write("%s\n",strBuffer);    if (SURFDATA.SplitBuffer1(strBuffer)==false) { logfile.Write("%s\n",strBuffer); continue; }long rc=SURFDATA.InsertTable();    if ( (rc>=3113) && (rc<=3115) ) return false; // 只要不是数据库session的错误,程序就继续。if (rc != 0) { logfile.Write("%s\n",strBuffer); continue; }}conn.commit();  File.CloseAndRemove();  //关闭文件指针,并删除文件logfile.WriteEx("成功(total=%d,insert=%d,update=%d,invalid=%d)。\n",SURFDATA.totalcount,SURFDATA.insertcount,SURFDATA.updatecount,SURFDATA.invalidcount);return true;
}
//_shqx.h
#ifndef _SHQX_H
#define _SHQX_H
#include "_public.h"
#include "_ooci.h"
struct st_stcode  //全国气象站点参数数据结构
{char provname[31];   // 省名称char obtid[11];      // 站点代码char cityname[31];   // 城市名double lat;          // 纬度double lon;          // 经度double height;       // 海拔高度
};
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/sint  r;              // 降雨量:0.1mmint  vis;            // 能见度:0.1米
};
struct st_signallog  //分区信号数据结构
{char obtid[11];char ddatetime[20];char signalname[2];char signalcolor[2];
};//111111111111111111111111111111111111111111111111.CSURFDATA类
class CSURFDATA
{public:int totalcount,insertcount,updatecount,invalidcount;  // 记录总数据、插入数、更新数、无效记录数。struct st_surfdata m_stsurfdata;CSURFDATA(connection *conn,CLogFile *logfile); //在构造函数里传进参数~CSURFDATA();void initdata();  // 数据初始化connection *m_conn; //在类里操作数据库需要一个指针,m_conn,m_logfile这两个成员需要给它们赋值CLogFile   *m_logfile; //在类里写日志,m_logfile->,类里不能再类实例化,所以定义为指针int iccount; //不能定义到成员函数里值会变sqlstatement stmtsel,stmtins,stmtupt;// 把用逗号分隔的记录拆分到m_stsurfdata结构中。bool SplitBuffer(const char *strBuffer);  // 把xml格式的记录拆分到m_stsurfdata结构中。bool SplitBuffer1(const char *strBuffer);// 把m_stsurfdata结构中的值更新到T_SURFDATA表中。long InsertTable();
};//11111111111111111111111111111111111111111111112.CSIGNALLOG类
class CSIGNALLOG
{public:int totalcount,insertcount,updatecount,invalidcount;  // 记录总数据、插入数、更新数、无效记录数。struct st_signallog m_stsignallog;vector<struct st_signallog> vsignallog;   // 容器存放一个文件的全部记录CSIGNALLOG(connection *conn,CLogFile *logfile);~CSIGNALLOG();void initdata();  // 数据初始化connection *m_conn;CLogFile   *m_logfile;int iccount;sqlstatement stmtsel,stmtins,stmtupt; bool SplitBuffer(const char *strBuffer);  // 把记录拆分到vsignallog容器中。  long InsertTable(); // 把vsignallog容器中的值更新到T_SIGNALDATA表中。
};//111111111111111111111111111111111111111113.把非结构化数据文件写入oracle数据库的表中
int FileToTable(connection *in_conn,CLogFile *in_logfile,char *in_tname,char *in_filename,char *in_ddatetime);
#endif
//_shqx.cpp
#include "_shqx.h"
//111111111111111111111111111111111111111111111111111111.CSURFDATA类
CSURFDATA::CSURFDATA(connection *conn,CLogFile *logfile)
{initdata();        // 构造函数里传入两个指针变量并赋初值m_conn=conn; m_logfile=logfile;  // 所以调用CSURFDATA(&conn,&logfile);就能完成初始化
}
void CSURFDATA::initdata()
{totalcount=insertcount=updatecount=invalidcount=0;m_conn=0; m_logfile=0;memset(&m_stsurfdata,0,sizeof(struct st_surfdata));
}
CSURFDATA::~CSURFDATA()
{}bool CSURFDATA::SplitBuffer(const char *strBuffer) //把用逗号分隔的记录拆分到m_stsurfdata结构中
{ totalcount++;memset(&m_stsurfdata,0,sizeof(struct st_surfdata));CCmdStr CmdStr;CmdStr.SplitToCmd(strBuffer,",",true);if (CmdStr.CmdCount()!=9) { invalidcount++; return false; }CmdStr.GetValue(0,m_stsurfdata.obtid,5);      // 站点代码CmdStr.GetValue(1,m_stsurfdata.ddatetime,19); // 数据时间:格式yyyy-mm-dd hh:mi:ss。double dtmp=0;CmdStr.GetValue(2,&dtmp); m_stsurfdata.t=(int)(dtmp*10);  // 气温:单位,0.1摄氏度CmdStr.GetValue(3,&dtmp); m_stsurfdata.p=(int)(dtmp*10);  // 气压:0.1百帕CmdStr.GetValue(4,&m_stsurfdata.u);  // 相对湿度,0-100之间的值。CmdStr.GetValue(5,&m_stsurfdata.wd); // 风向,0-360之间的值。CmdStr.GetValue(6,&dtmp); m_stsurfdata.wf=(int)(dtmp*10);  // 风速:单位0.1m/sCmdStr.GetValue(7,&dtmp); m_stsurfdata.r=(int)(dtmp*10);   // 降雨量:0.1mmCmdStr.GetValue(8,&dtmp); m_stsurfdata.vis=(int)(dtmp*10); // 能见度:0.1米return true;
}bool CSURFDATA::SplitBuffer1(const char *strBuffer) //把xml格式的记录拆分到m_stsurfdata结构中
{totalcount++;memset(&m_stsurfdata,0,sizeof(struct st_surfdata));GetXMLBuffer(strBuffer,"obtid",m_stsurfdata.obtid,5);      // 站点代码GetXMLBuffer(strBuffer,"ddatetime",m_stsurfdata.ddatetime,19); // 数据时间:格式yyyy-mm-dd hh:mi:ss。double dtmp=0;GetXMLBuffer(strBuffer,"t",&dtmp); m_stsurfdata.t=(int)(dtmp*10);  // 气温:单位,0.1摄氏度GetXMLBuffer(strBuffer,"p",&dtmp); m_stsurfdata.p=(int)(dtmp*10);  // 气压:0.1百帕GetXMLBuffer(strBuffer,"u",&m_stsurfdata.u);  // 相对湿度,0-100之间的值。GetXMLBuffer(strBuffer,"wd",&m_stsurfdata.wd);  // 风向,0-360之间的值。GetXMLBuffer(strBuffer,"wf",&dtmp); m_stsurfdata.wf=(int)(dtmp*10);  // 风速:单位0.1m/sGetXMLBuffer(strBuffer,"r",&dtmp); m_stsurfdata.r=(int)(dtmp*10);   // 降雨量:0.1mmGetXMLBuffer(strBuffer,"vis",&dtmp);  m_stsurfdata.vis=(int)(dtmp*10); // 能见度:0.1米return true;
}long CSURFDATA::InsertTable() //把m_stsurfdata结构中的值更新到T_SURFDATA表中
{if (stmtsel.m_state==0){stmtsel.connect(m_conn);stmtsel.prepare("select count(*) from T_SURFDATA where obtid=:1 and ddatetime=to_date(:2,'yyyy-mm-dd hh24:mi:ss')");stmtsel.bindin( 1, m_stsurfdata.obtid,5);stmtsel.bindin( 2, m_stsurfdata.ddatetime,19);stmtsel.bindout(1,&iccount);}if (stmtins.m_state==0){stmtins.connect(m_conn);stmtins.prepare("insert into T_SURFDATA(obtid,ddatetime,t,p,u,wd,wf,r,vis,crttime,keyid) values(:1,to_date(:2,'yyyy-mm-dd hh24:mi:ss'),:3,:4,:5,:6,:7,:8,:9,sysdate,SEQ_SURFDATA.nextval)");stmtins.bindin( 1, m_stsurfdata.obtid,5);stmtins.bindin( 2, m_stsurfdata.ddatetime,19);stmtins.bindin( 3,&m_stsurfdata.t);stmtins.bindin( 4,&m_stsurfdata.p);stmtins.bindin( 5,&m_stsurfdata.u);stmtins.bindin( 6,&m_stsurfdata.wd);stmtins.bindin( 7,&m_stsurfdata.wf);stmtins.bindin( 8,&m_stsurfdata.r);stmtins.bindin( 9,&m_stsurfdata.vis);}if (stmtupt.m_state==0){stmtupt.connect(m_conn);stmtupt.prepare("update T_SURFDATA set t=:1,p=:2,u=:3,wd=:4,wf=:5,r=:6,vis=:7 where obtid=:8 and ddatetime=to_date(:2,'yyyy-mm-dd hh24:mi:ss')");stmtupt.bindin( 1,&m_stsurfdata.t);stmtupt.bindin( 2,&m_stsurfdata.p);stmtupt.bindin( 3,&m_stsurfdata.u);stmtupt.bindin( 4,&m_stsurfdata.wd);stmtupt.bindin( 5,&m_stsurfdata.wf);stmtupt.bindin( 6,&m_stsurfdata.r);stmtupt.bindin( 7,&m_stsurfdata.vis);stmtupt.bindin( 8, m_stsurfdata.obtid,5);stmtupt.bindin( 9, m_stsurfdata.ddatetime,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 (iccount>0) {if (stmtupt.execute() != 0)   //执行更新的SQL语句,一定要判断返回值,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{   if (stmtins.execute() != 0)  // 执行插入的SQL语句,一定要判断返回值,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;
}//11111111111111111111111111111111111111111111111111111111111112.CSIGNALLOG类
CSIGNALLOG::CSIGNALLOG(connection *conn,CLogFile *logfile)
{initdata();m_conn=conn; m_logfile=logfile;
}
void CSIGNALLOG::initdata()
{totalcount=insertcount=updatecount=invalidcount=0;m_conn=0; m_logfile=0;memset(&m_stsignallog,0,sizeof(struct st_signallog));vsignallog.clear();
}
CSIGNALLOG::~CSIGNALLOG()
{}bool CSIGNALLOG::SplitBuffer(const char *strBuffer) //把记录拆分到vsignallog容器中
{vsignallog.clear();memset(&m_stsignallog,0,sizeof(struct st_signallog));CCmdStr CmdStr;  CmdStr.SplitToCmd(strBuffer," ",true);if (CmdStr.CmdCount()<3) { invalidcount++; return false; }CmdStr.GetValue(0,m_stsignallog.ddatetime,12); //数据时间:格式yyyymmddhh24mistrcat(m_stsignallog.ddatetime,"00");AddTime(m_stsignallog.ddatetime,m_stsignallog.ddatetime,8*60*60,"yyyy-mm-dd hh24:mi:ss");CmdStr.GetValue(1,m_stsignallog.obtid,4);   //站点代码char strtemp[11];for (int ii=3;ii<=CmdStr.CmdCount();ii++){ // 201809142353 GWTE A3000 ....= memset(strtemp,0,sizeof(strtemp));CmdStr.GetValue(ii-1,strtemp,5);  // m_stsignallog.signalname[0]表示字符串中第一个字符m_stsignallog.signalname[0]=strtemp[0]; //strtemp[0]就是Am_stsignallog.signalcolor[0]=strtemp[1]; //strtemp[1]就是3vsignallog.push_back(m_stsignallog);totalcount++;}return true;
}long CSIGNALLOG::InsertTable()  //把vsignallog容器中的值更新到T_SIGNALDATA表中
{ //可能会返回stmtupt.m_cda.rc,所以用longif (stmtsel.m_state==0){stmtsel.connect(m_conn);// 如下这个表的主键有三个字段stmtsel.prepare("select count(*) from T_SIGNALLOG where obtid=:1 and ddatetime=to_date(:2,'yyyy-mm-dd hh24:mi:ss') and signalname=:3");stmtsel.bindin( 1, m_stsignallog.obtid,4);stmtsel.bindin( 2, m_stsignallog.ddatetime,19);stmtsel.bindin( 3, m_stsignallog.signalname,1);stmtsel.bindout(1,&iccount);}if (stmtins.m_state==0){stmtins.connect(m_conn);stmtins.prepare("insert into T_SIGNALLOG(obtid,ddatetime,signalname,signalcolor,crttime,keyid) values(:1,to_date(:2,'yyyy-mm-dd hh24:mi:ss'),:3,:4,sysdate,SEQ_SIGNALLOG.nextval)");stmtins.bindin( 1, m_stsignallog.obtid,4);stmtins.bindin( 2, m_stsignallog.ddatetime,19);stmtins.bindin( 3, m_stsignallog.signalname,1);stmtins.bindin( 4, m_stsignallog.signalcolor,1);}if (stmtupt.m_state==0){stmtupt.connect(m_conn);stmtupt.prepare("update T_SIGNALLOG set signalcolor=:1 where obtid=:2 and ddatetime=to_date(:3,'yyyy-mm-dd hh24:mi:ss') and signalname=:4");stmtupt.bindin( 1, m_stsignallog.signalcolor,1);stmtupt.bindin( 2, m_stsignallog.obtid,4);stmtupt.bindin( 3, m_stsignallog.ddatetime,19);stmtupt.bindin( 4, m_stsignallog.signalname,1);}for (int ii=0;ii<vsignallog.size();ii++){ //把容器里的值拷出来memcpy(&m_stsignallog,&vsignallog[ii],sizeof(struct st_signallog));m_logfile->Write("%s,%s,%s,%s\n",m_stsignallog.obtid,m_stsignallog.ddatetime,m_stsignallog.signalname,m_stsignallog.signalcolor);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 (iccount>0) {    if (stmtupt.execute() != 0)   //执行更新的SQL语句,一定要判断返回值,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{      if (stmtins.execute() != 0)  //执行插入的SQL语句,一定要判断返回值,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;
}//1111111111111111111111111111111111111111111111113.把非结构化数据文件写入oracle数据库的表中
int FileToTable(connection *in_conn,CLogFile *in_logfile,char *in_tname,char *in_filename,char *in_ddatetime)
{sqlstatement stmt(in_conn);  int icount=0;  //判断文件记录在表中是否已存在stmt.prepare("select count(*) from %s where filename=:1",in_tname);stmt.bindin(1,in_filename,300);stmt.bindout(1,&icount);if (stmt.execute() != 0){in_logfile->Write("FileToTable() failed.%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return stmt.m_cda.rc;}stmt.next();  if (icount>0) return 0;  //如果记录已存在,直接返回0-成功。  //11111111111111111111111111111111111111111111111111111111111111111int ifilesize=FileSize(in_filename);  //把文件信息插入表中。stmt.prepare("\insert into %s(filename,ddatetime,filesize,filecontent,crttime,keyid)\values(:1,to_date(:2,'yyyymmddhh24miss'),:3,empty_blob(),sysdate,SEQ_%s.nextval)",\in_tname,in_tname+2);  stmt.bindin(1,in_filename,300); //empty_blob()可以换成null试试,文件内容可以不弄到blob字段stmt.bindin(2,in_ddatetime,14);stmt.bindin(3,&ifilesize);  if (stmt.execute() != 0){in_logfile->Write("FileToTable() failed.%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return stmt.m_cda.rc;}    //111111111111111111111111111111111111111111111111111111111111111stmt.prepare("select filecontent from %s where filename=:1 for update",in_tname);stmt.bindin(1,in_filename,300);   //把文件内容更新到BLOB字段中。stmt.bindblob();if (stmt.execute() != 0){in_logfile->Write("FileToTable() failed.%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return stmt.m_cda.rc;}    if (stmt.next() != 0) return -1; //获取一条记录,一定要判断返回值,0-成功,1403-无记录,其它-失败  if (stmt.filetolob((char *)in_filename) != 0) { //把磁盘文件pic_in.jpg的内容写入BLOB字段,一定要判断返回值,0-成功,其它-失败。in_logfile->Write("FileToTable() stmt.filetolob() failed.\n%s\n",stmt.m_cda.message); return -1;} in_conn->commit(); //图片数据大,一个文件提交一次return 0;
}

2.分区/表空间/网络/主键/错误优化:chown -R 用户

用文件夹代替实际分区。root用户mkdir htidc log data,htidc分public和shqx两个文件夹。如下授权给Oracle用户。

下面为改进makefile,PUBINCL中-I指定头文件_public.h,_ftp.h等等搜索目录,自己去找头文件。冒号前后整个一行等于下行编译命令。冒号后面文件有更新(必须要有一个同名cpp文件),则重新编译(只是有这个重编译功能),一般后面不放_ooci…因为稳定不需要改动。

# oracle头文件路径
ORAINCL = -I$(ORACLE_HOME)/rdbms/public
# oracle库文件路径
ORALIB =  -L$(ORACLE_HOME)/lib -L.
# oracle的oci库
ORALIBS = -lclntsh# 通用框架头文件路径
PUBINCL = -I/htidc/public/c
# 通用框架库文件路径
PUBCPP = /htidc/public/c/_public.cpp
FTPCPP = /htidc/public/c/_ftp.cpp
OCICPP = /htidc/public/c/_ooci.cppCC=g++
# CFLAGS = -O2
# CFLAGS = -O2 -Wall
CFLAGS = -g -Wno-write-strings -Wno-unused-variableall: crtsurfdata psurfdata psignallog wgetrain24\wgettemp24 pzhrain24filecrtsurfdata:crtsurfdata.cpp _shqx.h _shqx.cpp$(CC) $(CFLAGS) -o crtsurfdata crtsurfdata.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) $(PUBINCL) $(PUBCPP) $(OCICPP) _shqx.cpp -lm -lccp -f crtsurfdata ../bin/.psurfdata: psurfdata.cpp _shqx.h _shqx.cpp$(CC) $(CFLAGS) -o psurfdata psurfdata.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) $(PUBINCL) $(PUBCPP) $(OCICPP) _shqx.cpp -lm -lccp -f psurfdata ../bin/.pzhrain24file: pzhrain24file.cpp _shqx.h _shqx.cpp$(CC) $(CFLAGS) -o pzhrain24file pzhrain24file.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) $(PUBINCL) $(PUBCPP) $(OCICPP) _shqx.cpp -lm -lccp -f pzhrain24file ../bin/.psignallog: psignallog.cpp _shqx.h _shqx.cpp$(CC) $(CFLAGS) -o psignallog psignallog.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) $(PUBINCL) $(PUBCPP) $(OCICPP) _shqx.cpp -lm -lccp -f psignallog ../bin/.wgetrain24: wgetrain24.cpp $(CC) $(CFLAGS) -o wgetrain24 wgetrain24.cpp $(PUBINCL) $(PUBCPP) -lm -lccp -f wgetrain24 ../bin/.wgettemp24: wgetrain24.cpp $(CC) $(CFLAGS) -o wgettemp24 wgettemp24.cpp $(PUBINCL) $(PUBCPP) -lm -lccp -f wgettemp24 ../bin/.clean:rm -rf crtsurfdata psurfdata psignallog wgetrain24rm -rf wgettemp24 pzhrain24file

切换用户如下目录里的*.sh都会执行,和oracle名字无关。如上makefile中不需要数据库就不要包含路径。


如下crttable.sql里最后不写exit;的话下行登录sqlplus不退出,每行sql语句需要分号结尾。如下.sql文件里一般放一些系统初始化sql语句如建表,839行insert站点参数。snorcl11g_198是连远程该服务名指定的数据库,不加就连本地数据库。

oracle安装好后会自动创建几个表空间,表空间是用来存放数据库对象的一个空间,类似分区,如下是查看oracle表空间大小的sql(登录再执行)。

SELECT
a.tablespace_name, --表空间名
total, --表空间大小
free, --表空间剩余大小
(total-free), --表空间使用大小
Round((total-free)/total,4)*100 --使用率
FROM (SELECT tablespace_name,Sum(bytes) free
FROM DBA_FREE_SPACE
GROUP BY tablespace_name) a,
(SELECT tablespace_name,Sum(bytes) total
FROM DBA_DATA_FILES
GROUP BY tablespace_name)b
WHERE
a.tablespace_name=b.tablespace_name;

SYSTEM表空间(创建数据库时创建的)相当于win系统C盘,USERS表空间相当于D盘放数据,UNDOTBS1表空间相当于事务缓冲区,SYSAUX相当于SYSTEM表空间辅助分区。

创建新用户并指定该用户缺省表空间为users,vi creuser.sql。

--把数据库用户允许错误重试的次数改为不限制
alter profile DEFAULT limit FAILED_LOGIN_ATTEMPTS UNLIMITED;
alter profile DEFAULT limit PASSWORD_LIFE_TIME  UNLIMITED;-- 上海气象数据中心的主用户,shqx为用户名,pwdidc为密码,default tablespace users默认user表空间
-- drop user shqx cascade;
create user shqx profile default identified by pwdidc default tablespace users account unlock;
grant connect to shqx;
grant dba to shqx;exit;

下面是以超级用户登录,/ 指不用任何密码,不能远程登录只能登录本机且装有数据库。

如下是网络/主键/错误优化 :入库时查看日志,时间太长,truncate删除表记录继续入库时间测试。

如上连本机数据库1秒之内处理完,下面方式和不带服务名一样也不通过网络设备,日志都为1秒左右。

以上说明第一点:网络对性能影响大,下面是第二点:主键冲突(数据库已存在主键即有记录了,没有truncate)。


下面为改善:先去表中查下有没有这条记录存在,有的话就不插入insert入库,m_cda.rc报个错,这样能提高速度解决主键冲突。以下在psurfdata.cpp中,2个主键查询。bindin行,bindout列。

如下出现rc=1重复记录即主键冲突就不管,不等于1日志写错误信息并直接return false。

如上行出现问题logfile.write("stmtins.execute() fail…最后直接return false(-1)退出整个大循环,如下所示。

所以将return false改为continue(这个小循环下面不执行,重新从这个小循环开头执行),break(跳出小循环往后执行,不重小循环开头开始)。





如下oracle类似的错误代码是连在一起的,以下两个错必须退出(return false),其他的错没必要退出。

3.历史文件/表数据清理:生成测试数据后去采集,采集后未删除文件,因为数据不只一个系统用

一般两个需求:1.删除哪个时间点前文件(常用)2.只保留多少个文件(一般删除数据库归档日志)
1.以下是删除多长时间之前文件(生成或采集的.txt数据文件)。

//这个程序不写日志,deletefiles.cpp
#include "_public.h"
void EXIT(int sig);
void _help(char *argv[]);  //显示程序的帮助,argv[]未指定字符串长度int main(int argc,char *argv[])
{ //最后一个参数可有可无,如下argv是变量相当于&argv或&argv[0]if ( (argc != 3) && (argc != 4) ) { _help(argv); return -1; }   //CloseIOAndSignal(); // 关闭全部的信号和输入输出,可以先//了,因为调试时要输出信息// 处理程序退出的信号设置信号,在shell状态下可用 "kill + 进程号" 正常终止些进程,但请不要用 "kill -9 +进程号" 强行终止signal(SIGINT,EXIT); signal(SIGTERM,EXIT);    char   strPathName[201]; //strPathName:/data/shqx/ftp/surfdata,dDayOut,strTimeOutdouble dDayOut=0;memset(strPathName,0,sizeof(strPathName));strcpy(strPathName,argv[1]);  dDayOut=atof(argv[2]);    char strTimeOut[21];LocalTime(strTimeOut,"yyyy-mm-dd hh24:mi:ss",0-(int)(dDayOut*24*60*60)); //获取需要删的时间点存入strTimeOut中CDir Dir;  //strMatch:\"*.TXT,*.CSV\"char strMatch[50]; memset(strMatch,0,sizeof(strMatch));if (argc==3) strcpy(strMatch,"*"); //如果只有3个参数,全删else strcpy(strMatch,argv[3]);  //11111111111111111111111111111111111111111111111打开目录,读取文件,包括它的子目录if (Dir.OpenDir(strPathName,strMatch,10000,true,false) == false){printf("Dir.OpenDir(%s) failed.\n",strPathName); return -1;}char strLocalTime[21];while (Dir.ReadDir() == true){if (strcmp(Dir.m_ModifyTime,strTimeOut) > 0) continue; //m_ModifyTime大于strTimeOut的话就不用删除printf("delete %s ok.\n",Dir.m_FullFileName);REMOVE(Dir.m_FullFileName); //C语言提供了remove函数,在_public.cpp中重写了REMOVE,删不了多试几次}return 0;
}
void EXIT(int sig)
{printf("程序退出,sig=%d\n\n",sig);exit(0);
}//111111111111111111111111111111111111111111111显示程序的帮助
void _help(char *argv[])
{printf("\n");printf("Using:/htidc/public/bin/deletefiles pathname dayout [matchstr]\n");printf("Sample:/htidc/public/bin/deletefiles /data/shqx/ftp/surfdata 0.1 \"*.TXT,*.CSV\"\n\n");// dayout单位是天,如果要清除30分钟前数据,则dayout填30/(24*60),如上0.1*24*60=144分钟,就是当前时间往前推144分钟printf("本程序是数据中心的公共功能模块,用于删除指定目录下的历史文件。\n");printf("pathname 待清理的目录名,包括这个目录下的各级子目录。\n");printf("dayout   文件保留天数,单位是天,可以用小数。\n");printf("matchstr 待清理文件名的匹配规则,这是一个可选参数,可以匹配多种类型的文件,中间用逗号分隔,最好用双引号包含起来。\n\n");
}

deletefiles.cpp不用自身调度用crontab -e,最后一个参数可不写,写了必须加双引号。


下面改进,写日志后清空两个容器,在crtsurfdata.cpp中。


2.下面是第二个需求,保留多少文件。

//删除数据库的归档日志,deletearchive.cpp
#include "_public.h"
int main(int argc,char *argv[])
{char strPathName[201];int uSaveCount=0;if (argc != 3){printf("\n");printf("Using:/htidc/htidc/bin/deletearchive pathname savecount\n\n");printf("Example:/htidc/htidc/bin/procctl 300 /htidc/htidc/bin/deletearchive /oracle/archive 20\n\n");printf("本程序读取目定pathname录下的文件信息,并按时间降序,只保留最近savecount个文件,其它的都删除掉。\n");printf("本程序主要用于删除oracle数据库的归档日志文件。\n");printf("本程序不写日志文件,也不会在屏幕上输出任何信息。\n");printf("本程序调用/bin/ls -lt pathname获取归档日志文件信息。\n");printf("本程序可以手工运行,也可以由procctl调度。\n\n\n");printf("启用oracle归档日志的相关命令如下:\n");printf("sqlplus /nolog\n");printf("connect / as sysdba;\n");printf("alter system set log_archive_dest_1='location=/home/oracle/oradata/EJETDB/archive';\n");printf("shutdown immediate;\n");printf("startup mount;\n");printf("alter database archivelog;\n");printf("alter database open;\n");printf("alter system switch logfile;\n\n\n");return -1;}memset(strPathName,0,sizeof(strPathName));strcpy(strPathName,argv[1]);uSaveCount=atoi(argv[2]);// 关闭全部的信号和输入输出// 设置信号,在shell状态下可用 "kill + 进程号" 正常终止些进程// 但请不要用 "kill -9 +进程号" 强行终止CloseIOAndSignal(); FILE *fp=NULL;   //fp指向ls -l的输出的内容char strCmd[301];   //strPathName:/oracle/archivememset(strCmd,0,sizeof(strCmd)); sprintf(strCmd,"/bin/ls -lt %s",strPathName);  if ( (fp=popen(strCmd,"r")) == NULL ){printf("popen %s failed.\n",strCmd); return -1;}CCmdStr CmdStr;int uFetchedCount=0;char strBuffer[1024],strFullFileName[201];while (TRUE){memset(strBuffer,0,sizeof(strBuffer));if (FGETS(strBuffer,2000,fp) == FALSE) break;  uFetchedCount++;if (uFetchedCount <= uSaveCount + 1 ) continue;UpdateStr(strBuffer,"  "," ");   // Trim(strBuffer);CmdStr.SplitToCmd(strBuffer," ");memset(strBuffer,0,sizeof(strBuffer));CmdStr.GetValue(CmdStr.CmdCount()-1,strBuffer,200);memset(strFullFileName,0,sizeof(strFullFileName));snprintf(strFullFileName,200,"%s/%s",strPathName,strBuffer);REMOVE(strFullFileName);}pclose(fp);return 0;
}

3.下面为工具程序用于清理表中数据。

//deletetables.cpp
#include "_public.h"
#include "_ooci.h"
char logfilename[301];
char connstr[101];
char tname[51];
char where[1024];
char hourstr[101];
char localhour[21];
connection conn;
CLogFile logfile;
void EXIT(int sig);
void _help(char *argv[]); // 显示程序的帮助
int  maxcounts=500;  // 每批删除的记录数
bool _deletetables(); int main(int argc,char *argv[])
{if (argc != 2) { _help(argv); return -1; }memset(logfilename,0,sizeof(logfilename));memset(connstr,0,sizeof(connstr));memset(tname,0,sizeof(tname));memset(where,0,sizeof(where));memset(hourstr,0,sizeof(hourstr));GetXMLBuffer(argv[1],"logfilename",logfilename,300);GetXMLBuffer(argv[1],"connstr",connstr,100);GetXMLBuffer(argv[1],"tname",tname,50);GetXMLBuffer(argv[1],"where",where,1000);GetXMLBuffer(argv[1],"hourstr",hourstr,2000);//上面为获取参数放入一开始定义的几个char字符串中,下面是判断参数的合法性if (strlen(logfilename) == 0) { printf("logfilename is null.\n"); return -1; }if (strlen(connstr) == 0)     { printf("connstr is null.\n"); return -1; }if (strlen(tname) == 0)       { printf("tname is null.\n"); return -1; }if (strlen(where) == 1)       { printf("where is null.\n"); return -1; }if (strlen(hourstr) == 0)     { printf("hourstr is null.\n"); return -1; }CloseIOAndSignal();//关闭全部的信号和输入输出signal(SIGINT,EXIT); signal(SIGTERM,EXIT);//处理程序退出的信号if (logfile.Open(logfilename,"a+") == FALSE){printf("logfile.Open(%s) failed.\n",logfilename); return -1;}while (true) //自身调度,不用crontab{    memset(localhour,0,sizeof(localhour)); //判断当前时间是否在启动时间之内LocalTime(localhour,"hh24");if (strstr(hourstr,localhour)==0) { sleep(60); continue; }if (conn.connecttodb(connstr,"Simplified Chinese_China.ZHS16GBK") != 0){logfile.Write("connect database %s failed.\n",connstr); sleep(60); continue; }logfile.Write("delete table %s.\n",tname);if (_deletetables() == false) logfile.Write("deletetables failed.\n"); conn.disconnect();sleep(60); }return 0;
}
void EXIT(int sig)
{printf("程序退出,sig=%d\n\n",sig);exit(0);
}//11111111111111111111111111111111111111111显示程序的帮助
void _help(char *argv[])
{printf("\nUsing:/oracle/htidc/shqx/bin/deletetables \"<logfilename>/oracle/log/shqx/deletetables_SURFDATA.log</logfilename><connstr>shqx/pwdidc@snorcl11g_188</connstr><tname>T_SURFDATA</tname><where>where ddatetime<sysdate</where><hourstr>14,15,16</hourstr>\"\n\n");printf("这是一个工具程序,用于清理表中的数据。\n");printf("<logfilename>/log/shqx/deletetables_ALLAWSDATA.log</logfilename> 本程序运行日志文件名。\n");printf("<connstr>szidc/pwdidc@SZQX_10.153.97.251</connstr> 目的数据库的连接参数。\n");printf("<tname>T_ALLAWSDATA</tname> 待清理的表名。\n");printf("<where>where ddatetime<sysdate-5</where> 待清理数据的条件。\n");printf("<hourstr>01,02,03</hourstr> 本程序启动的时次,小时,时次之间用半角的逗号分隔开。\n\n");return;
}bool _deletetables()
{int  ccount=0;char strrowid[51],strrowidn[maxcounts][51];//sqlstatement stmt;//stmt.prepare("delete from %s %s",tname,where);//stmt.execute();//conn.commit();//如上这么写不行,如果表要删除的数据很多,delete from....这语句跑不动,不能让Oracle产生大事务//stmt.prepare("delete from %s %s" and rownum<10000",tname,where);//如上一次删除10000条,这种方法效率不高,假设where这个条件带的参数查这个数据时,假设这字段没有索引,那这sql执行时间相当长//111111111111111111111111111111111111111111111111获取符合条件的记录的rowidsqlstatement selstmt(&conn);selstmt.prepare("select rowid from %s %s",tname,where);selstmt.bindout(1, strrowid,50);if (selstmt.execute() != 0){logfile.Write("%s failed.\n%s\n",selstmt.m_sql,selstmt.m_cda.message); return false;}//1111111111111111111111111111111111111111生成删除数据的SQL语句,一次删除maxcounts条记录int ii=0;char strDeleteSQL[10241];memset(strDeleteSQL,0,sizeof(strDeleteSQL));sprintf(strDeleteSQL,"delete from %s where rowid in (",tname);char strtemp[11];for (ii=0; ii<maxcounts; ii++){memset(strtemp,0,sizeof(strtemp));if (ii==0) sprintf(strtemp,":%d",ii+1); //:号是sql绑定变量if (ii >0) sprintf(strtemp,",:%d",ii+1);strcat(strDeleteSQL,strtemp);}strcat(strDeleteSQL,")");sqlstatement delstmt(&conn);delstmt.prepare(strDeleteSQL);for (ii=0; ii<maxcounts; ii++){delstmt.bindin(ii+1,strrowidn[ii],50);}while (true){memset(strrowid,0,sizeof(strrowid));if (selstmt.next() != 0) break;strcpy(strrowidn[ccount],strrowid);ccount++;
//logfile.Write("%s\n",delstmt.m_sql);if (ccount == maxcounts){if (delstmt.execute() != 0){logfile.Write("delete %s failed.\n%s\n",tname,delstmt.m_cda.message); return false;}conn.commit();memset(strrowidn,0,sizeof(strrowidn));ccount=0;}//1111111111111111111111111111111111111删除的记录数到10000时提交一次事务,不让数据库产生大事务if (fmod(selstmt.m_cda.rpc,10000) < 1){logfile.Write("rows %d deleted.\n",selstmt.m_cda.rpc);//表里数据可能会非常多,几个小时都删不完,只要不在启动时间内就不干了,明天再说//干完活了,删除完记录了再判断当前时间是否在启动时间之内 memset(localhour,0,sizeof(localhour));LocalTime(localhour,"hh24");if (strstr(hourstr,localhour)==0) return true;}}//11111111111111111111111111111111111在以上循环处理的时候,如果不足maxcounts,就在这里处理for (ii=0; ii<ccount; ii++){delstmt.prepare("delete from %s where rowid=:1",tname);//剩下的一次删一条delstmt.bindin(1,strrowidn[ii],50);
//logfile.Write("%s\n",delstmt.m_sql);if (delstmt.execute() != 0){if (delstmt.m_cda.rc != 1){logfile.Write("delete %s failed.\n%s\n",tname,delstmt.m_cda.message); return false;}}}logfile.Write("rows %d deleted.completed.\n",selstmt.m_cda.rpc);conn.commit();return true;
}

如下0.7天前就是0.7*24=16.8,即16.8个小时前(1小时前大约0.04天前)。

vi /log/shqx/deletetables_…log(如上文件名)如下。

执行一条sql语句就会删除500条,最后不到500,一条一条删日志如下。


4.站点参数建表入表/PowerDesigner/主外键:g/./s//./g,多表查询

vi crttable.sql,T_OBTCODE这个表没必要创建索引,因为数据量很少。

drop table T_OBTCODE;
create table T_OBTCODE
(obtid      char(5),cityname   varchar2(30),provname   varchar2(30),lat        number(5,2),lon        number(5,2),height     number(8,2),rsts       number(1),    --状态:1-启用,2-禁用,3-故障primary key(obtid)
);




如下图整列(列操作)插入',1);,技巧:alt+shift+鼠标拖动右边滚条到最低+鼠标点击最低。如下取消勾选全词匹配。


vi T_OBTCODE.sql将上面列操作实现的sql全部复制进去。




vi T_OBTCODE.sql,改完后。

PowerDesigner安装链接:https://pan.baidu.com/s/1TR5tT6qh7G4CVPDFxZ7_wg 提取码:vx9m 。

将上面汉化…文件夹里文件全复制替换到下面安装目录中(可改变安装目录)。

上海气象.pdm文件:链接:https://pan.baidu.com/s/1zkzGDQuggwZhd1oNobeVqQ 提取码:0ad6 。

P:主键,F:外键,M:勾上不允许为空。

下面为保存并生成.sql文件。

如下还要将双引号替换为空,不同数据库生成不同sql语句,如下修改设置就不生成双引号了。

1.下面为主键命名,主键在Columns里p字段已指定。

如下是主键的另一种写法。

2.下面为创建索引


3.下面为创建表空间,如下将表存入名为USERS的表空间。

如下将索引存入名为INDEXS表空间。

如下主键就是索引也有这些参数也扔入INDEXS表空间。

4.字段值附上约束条件,如果复制其他表记得删除字段值约束条件

5.如下U是unique index,记录序号即keyid是唯一约束,第三行是数据时间。

下面是创建序列。

ctrl+G生成.sql文件,注意主键名不要重复,双引号替换为空。复制刚生成的.sql文件内容到crttable.sql中,执行如下命令必须其他窗口SQL>exit

1.创建主外键约束,站点代码在如下左表里是主键,在右表是外键,命名为:FK_子表_父表。在SURFDATA(右)表上建立了外键约束,如下图标是创建主外键连接线。如下<pk,fk>,pk主键勾上p字段,fk外键勾上f字段。

如下 多从外 引出。


2.下面演示出错情况,建立这种约束后有什么效果,双击主外键约束线。ctrl+G生成crebas.sql文件,复制到crttable.sql。

:g/"/s// /g

3.如果表被锁住(未提交)资源忙超时,dbshut关数据库再开。左边updata只有none和restrict两个选项。如下两个都为restrict为父表删不了子表已经在用的记录。


将上面复制修改到下面crttable.sql中,之前有生成脚本写入过,这里只要修改下最后就行。

如下删除59493等等其他的可以删除,但59287不行,因为已经在查询中用了,所以如下为上面两个Restrict效果。

4.父表删一条记录,子表和它相关的记录就被删。

preview将引号换为空格,复制粘贴到SQL>(先登录SQL),不用重新建表。

如下是多表查询,想用一个sql语句查出数据同时也将站点名称obtname也查出来。

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

  1. 【数据库2】生成txt/xml文件,ftp,oracle安装/表操作/虚表/日期/序列/索引/视图/链路/同义词/高可用性,mysql/文件入库/清理/表结构设计/交换/收集

    文章目录 1.生成数据:crontab 2.ftp:ftp是tcp/ip协议族中一员,分客户端和服务端 2.1 安装:linux操作系统的用户也是ftp的用户,可以配置专用的ftp用户,专用的ftp用 ...

  2. 精通LINQ--11.4.3 修改XML文件中的元素

    原文地址:https://blog.csdn.net/linqmail/article/details/2341575 使用LINQ to XML还可以修改XML文件中的元素.下面的实例代码使用LIN ...

  3. python把c语言的.h文件转为c++的.cpp和.h文件

    把c转为c++对象 c文件内容 typedef struct ast_value_t {ast_metadata meta;ast_value_data data;ast_value_type typ ...

  4. 使用DOM生成XML文件(转)

    http://www.51cto.com/art/200704/46743.htm   6.11  使用DOM生成XML文件 解析器通过在内存中建立和XML结构相对应的树状结构数据,使得应用程序可以方 ...

  5. drugbank下载XML文件解析

    目录 HTML简介 什么是HTML HTML 标签 HTML 文档 = 网页 H使用 Notepad 或 TextEdit 来编写 HTML 步骤一:启动记事本 步骤一:启动记事本 步骤二:用记事本来 ...

  6. 创建带有关联的 XML 架构的 XML 文件 从 XML 文件创建 XML 架构

    一.创建带有关联的XML 架构的XML 文件 1.创建新的 Windows 应用程序项目 首先需要在 Visual Basic 或 Visual C# 中创建新的 Windows 应用程序.创建一个新 ...

  7. 简单XML文件C#操作方法

    XML数据文件灵活而强大,在C#中,操作起来也十分方便.我们常用XML文件保存少量的数据,如系统配置信息,用户个性数据...,而对这些数据的操作最常用的就是读取,写入和删除相关的结点.本人的实际的应用 ...

  8. html5 xml在线编辑,xml在线(在线编辑xml文件)

    1.xenu link sleuth可同时生成html格式地图(适用于小型站点)和xml格式地图.2.xml sitemap在线生成工具,网站地址很多时,会比较浪费时间,想生成所有,则需要收. ]&g ...

  9. XML文件的数据抽取

    目录 一.XML文件介绍 二.XML文件的主要用途 三.案例介绍 数据准备 四.案例实现 1.建立转换 2.配置控件 3.保存运行转换 一.XML文件介绍 XML是一种可扩展标记语言,也是一种元标记语 ...

最新文章

  1. java itext 设计器_使用Java组件itext 生成pdf的介绍
  2. OvS、OvS-DPDK、VPP 基准性能对比
  3. 【ESP8266】NONOS SDK开发,串口发送、接收与中断
  4. dapper使用时性能优化
  5. python数据类型取值范围_Python基本数据类型(一)
  6. mysql binlog c++_MySQL binlog的格式解析
  7. 完成3DM以后的总结(2).Xutils的简单使用
  8. Java-final最终修饰符
  9. 个别计价法、先进先出法、加权平均法、移动加权平均法解读
  10. IIS6.0PUT漏洞复现
  11. 屏蔽拼多多广告信息的方法
  12. Python实例---爬取下载喜马拉雅音频文件
  13. 高速数据线缆自动化测试系统软件NSAT-1000
  14. poj 1102 LC-Display(模拟)
  15. 富人越富,穷人越穷,我为什么反对PoS
  16. Java中String,StringBuffer,StringBuilder基础知识
  17. 计算机说话技巧,随机应变的说话技巧
  18. 偷袭“懒人经济“的自热食品,是一门赚钱的好生意吗?
  19. Emscripten的研究与学习 --- 初探Emscripten
  20. 豆瓣电影Top250 步骤解析

热门文章

  1. 在Ubutun 14.04 Desktop LTS上部署Hadoop 2.7.1(伪分布式)
  2. easy ui 使用总结
  3. TP-Link无线网卡一对多的桥接
  4. Web安装项目创建桌面快捷方式
  5. 在Java、C#和C++中遍历集合
  6. linux编译动态库未定义,自定义动态库 对‘*’未定义的引用解决方法
  7. frontpage中html编辑,FrontPage教程编辑网页
  8. linux 修改默认路径吗,linux中vsftp修改默认路径
  9. flutter显示图标_如何让 Flutter 应用更好地使用 SVG?
  10. python如何创建模块教程_Python创建模块及模块导入的方法