【database3】oracle:数据交换/存储/收集

文章目录

  • 1.oracle安装:swap,dd
    • 1.1 创建swap交换区:grep MemTotal /proc/meminfo (安装Oracle物理内存要求1024MB以上),grep SwapTotal /proc/meminfo
    • 1.2 安装依赖包及改系统核心参数:关闭一些系统对数据库的限制,pam.d,inittab
    • 1.3 数据库的启动和关闭:oracle用户登录,lsnrctl start/stop/status 启动/关闭网络监听服务,dbstart/dbshut 启动/关闭数据库
    • 1.4 sqlplus命令行登录数据库:用oracle用户登录,执行sqlplus scott/tiger,以scott用户的身份登录
    • 1.5 plsql客户端登录数据库:远程连接需打开监听lsnrctl start
  • 2.C语言操作oracle:trim,rc,库/头文件
    • 2.1 makefile:-Wno-unused-variable变量未使用关闭警告(如int cc;下面未使用cc变量)
    • 2.2 createtable.cpp:setenv/putenv设置环境变量,char补空格,varchar不补空格。确定长度用char快,varchar2(4000)用到几个字符自动分配几个而不是一下给4000字符
    • 2.3 inserttable.cpp:truncate删除表中全部数据,不产生事务
    • 2.4 selecttable.cpp:stmt.m_cda.rpc变量保存了SQL执行后影响的记录数
    • 2.5 updatetable.cpp:连接数据库,返回值0成功,其它失败,失败代码在conn.m_cda.rc中,失败描述在conn.m_cda.message中
    • 2.6 deletetable.cpp:删除商品表中数据
    • 2.7 execplsql.cpp:执行一个PL/SQL过程
  • 3.虚表/日期/序列:ntp&hwclock
  • 4.索引/视图/链路/同义词:create index/view/link/synonym,distinct
  • 5.系统高可用性:12个1T组合,rac
  • 6.txt/xml文件入表:结构体内容
  • 7.站点参数建表入表/PowerDesigner/主外键:多表查询
  • 8.数据交换:数据导出为文件,数据文件推送
  • 9.非结构化数据存储:blob,pzhrain24file
  • 10.磁盘/cpu信息收集:内存信息free -m,和top命令查看的内存是一样的,也在系统文件/proc/meminfo


1.oracle安装:swap,dd

1.1 创建swap交换区:grep MemTotal /proc/meminfo (安装Oracle物理内存要求1024MB以上),grep SwapTotal /proc/meminfo

在这里插入图片描述
下面为添加交换区大小,此方法不限于centos,linux均适用,以下命令均需在root帐号下操作:
(1)先用free -m查看一下swap的大小。
在这里插入图片描述
(2)使用dd命令创建/home/swap这么一个分区文件。
在这里插入图片描述
(3)接着再把这个分区变成swap分区。
在这里插入图片描述
(4)再接着使用这个swap分区。使其成为有效状态。
在这里插入图片描述
(5)现在再用free -m命令查看一下内存和swap分区大小,就发现增加了2048M的空间了。创建的是2048,显示1999。
在这里插入图片描述
(6)修改/etc/fstab文件,让CentOS操作系统在每次重启时自动加载/home/swap交换区。上面执行错可以删除交换分区rm /home/swap,对了不用删。停止正在使用的swap分区:swapoff /home/swap。
在这里插入图片描述

1.2 安装依赖包及改系统核心参数:关闭一些系统对数据库的限制,pam.d,inittab

yum install -y binutils* compat-libstdc* elfutils-libelf* gcc* glibc* ksh* libaio* libgcc* libstdc* make* sysstat* libXp*  glibc-kernheaders
yum install -y ksh binutils compat-libstdc++-33 elfutils-libelf elfutils-libelf-devel gcc gcc-c++ glibc glibc-common glibc-devel libaio libaio-devel libgcc libstdc++ libstdc++-devel make numactl sysstat libXp unixODBC unixODBC-devel

1.vi /etc/sysctl.conf。
在文件最后增加以下行。
fs.file-max = 6815744
fs.aio-max-nr = 1048576
kernel.shmall = 2097152
kernel.shmmax= 2147483648
kernel.shmmni= 4096
kernel.sem = 250 32000100 128
net.ipv4.ip_local_port_range= 9000 65500
net.core.rmem_default= 262144
net.core.rmem_max= 4194304
net.core.wmem_default = 262144
net.core.wmem_max= 1048576
注意,kernel.shmmax参数的值为操作系统内存的一半,单位是字节。例如,装服务器的总物理内存如果是1024MB,那么kernel.shmmax的值应该是512乘1024乘1024=536870912,即kernel.shmmax = 536870912,其它的参数照抄。
2.vi /etc/security/limits.conf。
修改操作系统对oracle用户资源的限制。在该文件中添加如下行:
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536
oracle hard stack 10240
3.vi /etc/pam.d/login。
session required /lib/security/pam_limits.so
4.vi /etc/profile。

if [ $USER = "oracle" ]; then
        if [ $SHELL = "/bin/ksh" ]; then
              ulimit -p 16384
              ulimit -n 65536
        else
              ulimit -u 16384 -n 65536
        fi
fi

5.vi /etc/selinux/config,修改成 selinux=disabled。
6.关闭图形界面,vi /etc/inittab,把最后一行运行级别改为3,没有的话就不执行这一步。
在这里插入图片描述
7.重启服务器 #init 6 或 reboot。

从win本地上传oracle11g1.tgz压缩包到linux的tmp目录。用oracle用户登录,从根目录下开始解开压缩包,链接:https://pan.baidu.com/s/1Ywtv8zzRGzSCpwu9PyPobQ,提取码:ebk7 。
在这里插入图片描述
解压缩包后,一定要退出oracle用户exitctrl+d,否则oracle用户的环境变量不会生效。oracle11gR2.tgz解压后,会生成/oracle/.bash_profile文件,包括了Oracle数据库的安装参数,内容如下:

export ORACLE_BASE=/oracle/base
export ORACLE_HOME=/oracle/home
export ORACLE_SID=snorcl11g
export NLS_LANG='Simplified Chinese_China.ZHS16GBK'
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/usr/lib
export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin:.

1.3 数据库的启动和关闭:oracle用户登录,lsnrctl start/stop/status 启动/关闭网络监听服务,dbstart/dbshut 启动/关闭数据库

oracle数据库的启动和关闭配置成系统服务:在操作系统启动/关闭时自动启动/关闭Oracle实例和监听,以下都在root用户操作:
1.启动数据库实例的SQL脚本:vi /oracle/home/bin/dbstart,chmod +x

sqlplus / as sysdba <<EOF
startup;
EOF

2.vi /oracle/home/bin/dbrestart,chmod +x

sqlplus / as sysdba <<EOF
shutdown immediate;
startup;
EOF

3.vi /oracle/home/bin/dbshut,chmod +x

sqlplus / as sysdba <<EOF
shutdown immediate;
EOF

4.vi /usr/lib/systemd/system/oracle.service(/usr/lib文件夹里有一些.so文件,/systemd/system/oracle.service是自己创建的)

[Unit]
Description=Oracle RDBMS
After=network.target
 
[Service]
Type=simple
ExecStart=/usr/bin/su - oracle -c "/oracle/home/bin/dbstart >> /tmp/oracle.log"
ExecReload=/usr/bin/su - oracle -c "/oracle/home/bin/dbrestart >> /tmp/oracle.log"
ExecStop=/usr/bin/su - oracle -c "/oracle/home/bin/dbshut >> /tmp/oracle.log"
RemainAfterExit=yes
 
[Install]
WantedBy=multi-user.target

vi /usr/lib/systemd/system/lsnrctl.service

[Unit]
Description=Oracle RDBMS
After=network.target
 
[Service]
Type=simple
ExecStart=/usr/bin/su - oracle -c "/oracle/home/bin/lsnrctl start >> /tmp/lsnrctl.log"
ExecReload=/usr/bin/su - oracle -c "/oracle/home/bin/lsnrctl reload >> /tmp/lsnrctl.log"
ExecStop=/usr/bin/su - oracle -c "/oracle/home/bin/lsnrctl stop >> /tmp/lsnrctl.log"
RemainAfterExit=yes
 
[Install]
WantedBy=multi-user.target

5.如下命令可不执行。
systemctl daemon-reload # 重新加载服务配置文件
systemctl start oracle # 启动oracle服务。
systemctl restart oracle # 重启oracle服务。
systemctl stop oracle # 关闭oracle服务。
systemctl start lsnrctl # 启动lsnrctl服务。
systemctl restart lsnrctl # 重启lsnrctl服务。
systemctl stop lsnrctl # 关闭lsnrctl服务。
6.systemctl enable oracle # 把Oracle实例服务设置为开机自启动。
systemctl enable lsnrctl # 把Oracle监听服务设置为开机自启动。
7.Oracle实例启动的日志在/tmp/oracle.log文件中。监听的启动日成在/tmp/lsnrctl.log文件中。只有通过systemctl启动/关闭Oracle实例和监听才会写日志,手工执行脚本不写日志。

1.4 sqlplus命令行登录数据库:用oracle用户登录,执行sqlplus scott/tiger,以scott用户的身份登录

防火墙放开1521端口sqlplus登录数据库,centos7和centos6的防火墙设置不同,centos7采用以下方法:systemctl restart firewalld.service设完端口前后防火墙都重启下,firewall-cmd --list-ports查下放开的端口。
#firewall-cmd --zone=public --add-port=1521/tcp --permanent
在这里插入图片描述
启动监听:lsnrctl status,如下关闭防火墙:
在这里插入图片描述

1.5 plsql客户端登录数据库:远程连接需打开监听lsnrctl start

1.客户端环境:win64_11gR2_client链接:https://pan.baidu.com/s/1xLzrXAZm3xM-szds1IoQFw,提取码:mlo8 ,解压后点击set up应用程序进行安装。
2.客户端界面:链接:https://pan.baidu.com/s/1H9WIojcMbyqTBZe_goO-1Q 提取码:fp2u ,点击直接安装。
3.客户端参数配置文件
D:\app\w\product\11.2.0\client_1\network\admin\tnsnames.ora

snorcl11g_138 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.149.138)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SID = snorcl11g)
      (SERVER = DEDICATED)
    )
  )

如上是客户端,如下是服务端,参数内容与上相同,snorcl11g_138:是随便起的。
在这里插入图片描述

2.C语言操作oracle:trim,rc,库/头文件

2.1 makefile:-Wno-unused-variable变量未使用关闭警告(如int cc;下面未使用cc变量)

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

# oracle库文件路径  #-L指定库文件的搜索目录/oracle/home/lib
ORALIB =  -L$(ORACLE_HOME)/lib -L.

# oracle的oci库  #-l指定链接库名libclntsh.so
ORALIBS = -lclntsh

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

all: createtable inserttable selecttable updatetable deletetable execplsql

createtable:createtable.cpp _ooci.h _ooci.cpp
        g++ $(CFLAGS) -o createtable createtable.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _ooci.cpp

inserttable:inserttable.cpp _ooci.h _ooci.cpp
        g++ $(CFLAGS) -o inserttable inserttable.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _ooci.cpp

selecttable:selecttable.cpp _ooci.h _ooci.cpp
        g++ $(CFLAGS) -o selecttable selecttable.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _ooci.cpp

updatetable:updatetable.cpp _ooci.h _ooci.cpp
        g++ $(CFLAGS) -o updatetable updatetable.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _ooci.cpp

deletetable:deletetable.cpp _ooci.h _ooci.cpp
        g++ $(CFLAGS) -o deletetable deletetable.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _ooci.cpp

execplsql:execplsql.cpp _ooci.h _ooci.cpp
        g++ $(CFLAGS) -o execplsql execplsql.cpp $(ORAINCL) $(ORALIB) $(ORALIBS) _ooci.cpp

-Wno-write-string没有这行的话可将createtable.cpp中警告的字符串前加上(char*)就行。
在这里插入图片描述
还可以在声明时_ooci.h加const,_ooci.cpp中也要修改(不建议)。
在这里插入图片描述
如下-g是可调试。
在这里插入图片描述
如下全部采用标准写法:头路径,库路径+库名
在这里插入图片描述
在这里插入图片描述
如下采用原始不含头文件编译方法错误。
在这里插入图片描述
在这里插入图片描述
如下采用ORACLE_HOME换用户时只需要添加该用户.bash_profile中export…进env,不需要改makefile。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面是文件:
在这里插入图片描述
在这里插入图片描述
如下程序只要链接了动态库就需要LD…。
在这里插入图片描述
在这里插入图片描述

2.2 createtable.cpp:setenv/putenv设置环境变量,char补空格,varchar不补空格。确定长度用char快,varchar2(4000)用到几个字符自动分配几个而不是一下给4000字符

#include "_ooci.h"
int main(int argc,char *argv[])
{
//11111111111111111111111111111111111111111111111111111111.数据库连接池类
  connection conn;
  // 连接数据库,返回值0-成功,其它-失败
  // 失败代码在conn.m_cda.rc中,失败描述在conn.m_cda.message中。
  if (conn.connecttodb("scott/tiger@snorcl11g_138","Simplified Chinese_China.ZHS16GBK") != 0)
  {
    printf("connect database failed.\n%s\n",conn.m_cda.message); return -1;
  }

//11111111111111111111111111111111111111111111111112.SQL语言操作类
  sqlstatement stmt(&conn);  //不需要判断返回值
  // 准备创建表的SQL,商品表:商品编号id,商品名称name,价格sal,入库时间btime,商品说明memo,商品图片pic
  // prepare方法不需要判断返回值
  stmt.prepare("\
    create table goods(id    number(10),\
                       name  varchar2(30),\
                       sal   number(10,2),\
                       btime date,\
                       memo  clob,\
                       pic   blob,\
                       primary key (id))");

//111111111111111111111111111111111111111111111113.执行SQL语句,一定要判断返回值,0-成功,其它-失败
  if (stmt.execute() != 0)
  {
    printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
  }
  printf("create table goods ok.\n");
  return 0;
}

在这里插入图片描述
如下trim(c1)去除c1的空格,最后一行不加trim是查不出下面表格。CLOB:结构化数据如文本信息。BLOB:非结构化数据。
在这里插入图片描述

2.3 inserttable.cpp:truncate删除表中全部数据,不产生事务

// 本程序演示向商品表中插入10条记录。
#include "_ooci.h"
// 定义用于操作数据的结构,与表中的字段对应
struct st_GOODS  //结构体值与数据库中表即与createtable.cpp中表对应
{
  long id;          // 商品编号,用long数据类型对应oracle无小数的number
  char name[31];    // 商品名称,用char对应oracle的varchar2,注意,表中字段的长度是30,char定义的长度是31,要留C语言的结束符
  double sal;       // 商品价格,用double数据类型对应oracle有小数的number
  char btime[20];   // 入库时间,用char对应oracle的date,格式可以在SQL语句中指定,本程序将指定为yyyy-mm-dd hh24:mi:ss
} stgoods;

int main(int argc,char *argv[])
{
//111111111111111111111111111111111111111111111111.数据库连接池
  connection conn;
  // 连接数据库,返回值0-成功,其它-失败
  // 失败代码在conn.m_cda.rc中,失败描述在conn.m_cda.message中。
  if (conn.connecttodb("scott/tiger@snorcl11g_138","Simplified Chinese_China.ZHS16GBK") != 0)
  {
    printf("connect database failed.\n%s\n",conn.m_cda.message); return -1;
  }
    
//111111111111111111111111111111111111111111111112.SQL语言操作类
  sqlstatement stmt(&conn);
  // 准备插入数据的SQL,不需要判断返回值
  stmt.prepare("\
    insert into goods(id,name,sal,btime) \
                values(:1,:2,:3,to_date(:4,'yyyy-mm-dd hh24:mi:ss'))");
                //to_date(:4,'yyyy-mm-dd hh24:mi:ss')可为null
                //goods(id,name,sal,btime)字段在createtable.cpp已创建
  // 为SQL语句绑定输入变量的地址,行
  stmt.bindin(1,&stgoods.id);//bindin中的1对应上面:1
  stmt.bindin(2, stgoods.name,30); //30为长度,char是这样绑定
  stmt.bindin(3,&stgoods.sal);  //此时stgoods.id结构体变量们还未赋值
  stmt.bindin(4, stgoods.btime,19);

//111111111111111111111111111111111111111111111113.模拟商品数据,向表中插入10条测试信息
  for (int ii=1;ii<=10;ii++)
  {
    // 结构体变量初始化
    memset(&stgoods,0,sizeof(stgoods));
    // 为结构体的变量赋值
    stgoods.id=ii;
    sprintf(stgoods.name,"商品名称%02d",ii);
    stgoods.sal=ii*2.11;
    strcpy(stgoods.btime,"2018-03-01 12:25:31");
    // 每次指定变量的值后,执行SQL语句,一定要判断返回值,0-成功,其它-失败。
    if (stmt.execute() != 0) //每执行一次把变量值插入表,返回结构体m_cda.rc
    {
      printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
    }
    printf("insert ok(id=%d,rpc=%ld).\n",ii,stmt.m_cda.rpc); //rpc为行数
  }
  printf("insert table goods ok.\n");
  // 提交数据库事务,不提交的话程序退出,缺省回滚事务
  conn.commit();
  return 0;
}

在这里插入图片描述
在这里插入图片描述
注释//conn.commit();则insert后查询无记录,如下开启自动提交。
在这里插入图片描述

2.4 selecttable.cpp:stmt.m_cda.rpc变量保存了SQL执行后影响的记录数

//本程序演示从商品表中查询数据
#include "_ooci.h"
// 定义用于查询数据的结构,与表中的字段对应
struct st_GOODS  //和inserttable.cpp中结构体一样
{
  long id;          // 商品编号,用long数据类型对应oracle无小数的number
  char name[31];    // 商品名称,用char对应oracle的varchar2,注意,表中字段的长度是30,char定义的长度是31,要留C语言的结束符
  double sal;       // 商品价格,用double数据类型对应oracle有小数的number
  char btime[20];   // 入库时间,用char对应oracle的date,格式可以在SQL语句中指定,本程序将指定为yyyy-mm-dd hh24:mi:ss
} stgoods;

int main(int argc,char *argv[])
{
//111111111111111111111111111111111111111111111111.数据库连接池
  connection conn; 
  // 连接数据库,返回值0-成功,其它-失败
  // 失败代码在conn.m_cda.rc中,失败描述在conn.m_cda.message中
  if (conn.connecttodb("scott/tiger@snorcl11g_138","Simplified Chinese_China.ZHS16GBK") != 0)
  {
    printf("connect database failed.\n%s\n",conn.m_cda.message); return -1;
  }
    
//111111111111111111111111111111111111111111111112.SQL语言操作类
  sqlstatement stmt(&conn);
  int iminid,imaxid;
  // 准备查询数据的SQL,不需要判断返回值
  stmt.prepare("\
    select id,name,sal,to_char(btime,'yyyy-mm-dd hh24:mi:ss') from goods where id>:1 and id<:2");
  //id,name,sal,to_char(btime,'yyyy-mm-dd hh24:mi:ss')是输出变量
  //id>:1 and id<:2是输入变量  
  // 为SQL语句绑定输入变量的地址
  stmt.bindin(1,&iminid);
  stmt.bindin(2,&imaxid);
  // 为SQL语句绑定输出变量的地址
  // stgoods.id这些变量在inserttable已经赋过值
  stmt.bindout(1,&stgoods.id); 
  stmt.bindout(2, stgoods.name,30);
  stmt.bindout(3,&stgoods.sal);
  stmt.bindout(4, stgoods.btime,19);
  // 手工指定id的范围为1到5,执行一次查询 //inserttable已插入10条记录
  iminid=1;
  imaxid=5;

//111111111111111111111111111111111111111111111113.执行SQL语句,一定要判断返回值,0-成功,其它-失败
  if (stmt.execute() != 0)
  {
    printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
  }
  //上面执行完sql语句就得到一个结果集,怎么获取这结果集呢?用next方法
  while (1)
  {
    // 先把结构体变量初始化,然后才获取记录
    memset(&stgoods,0,sizeof(stgoods));
    // 获取一条记录,一定要判断返回值,0-成功,1403-无记录,其它-失败
    // 在实际应用中,除了0和1403,其它的情况极少出现。
    if (stmt.next() !=0) break;//每next一次就从结果集里拿一条数据    
    // 把获取到的记录的值打印出来
        printf("id=%ld,name=%s,sal=%.02f,btime=%s\n",stgoods.id,stgoods.name,stgoods.sal,stgoods.btime);
  }
  printf("本次查询了goods表%ld条记录。\n",stmt.m_cda.rpc);  
  return 0;
}

2.5 updatetable.cpp:连接数据库,返回值0成功,其它失败,失败代码在conn.m_cda.rc中,失败描述在conn.m_cda.message中

// 本程序演示更新商品表中数据
#include "_ooci.h"
int main(int argc,char *argv[])
{
//111111111111111111111111111111111111111111111111.数据库连接池
  connection conn;  
  if (conn.connecttodb("scott/tiger@snorcl11g_138","Simplified Chinese_China.ZHS16GBK") != 0)
  {
    printf("connect database failed.\n%s\n",conn.m_cda.message); return -1;
  }
    
//111111111111111111111111111111111111111111111112.SQL语言操作类
  sqlstatement stmt(&conn);
  int iminid,imaxid;
  char strbtime[20];
  // 准备更新数据的SQL,不需要判断返回值
  stmt.prepare("\
    update goods set btime=to_date(:1,'yyyy-mm-dd hh24:mi:ss') where id>:2 and id<:3");
  // 为SQL语句绑定输入变量的地址
  stmt.bindin(1, strbtime,19);  //1对应上面:1
  stmt.bindin(2,&iminid);  //2对应上面:2
  stmt.bindin(3,&imaxid);
  // 手工指定id的范围为1到5,btime为2017-12-20 09:45:30,执行一次更新
  iminid=1;
  imaxid=5;
  memset(strbtime,0,sizeof(strbtime));
  strcpy(strbtime,"2017-12-20 09:45:30");

//111111111111111111111111111111111111111111111113.执行SQL语句,一定要判断返回值,0-成功,其它-失败。
  if (stmt.execute() != 0)
  {
    printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
  }
  // 请注意,stmt.m_cda.rpc变量非常重要,它保存了SQL被执行后影响的记录数。
  printf("本次更新了goods表%ld条记录。\n",stmt.m_cda.rpc);
  // 提交事务
  conn.commit();
  return 0;
}

2.6 deletetable.cpp:删除商品表中数据

#include "_ooci.h"
int main(int argc,char *argv[])
{
//111111111111111111111111111111111111111111111111.数据库连接池
  connection conn;  
  if (conn.connecttodb("scott/tiger@snorcl11g_138","Simplified Chinese_China.ZHS16GBK") != 0)
  {
    printf("connect database failed.\n%s\n",conn.m_cda.message); return -1;
  }
    
//111111111111111111111111111111111111111111111112.SQL语言操作类
  sqlstatement stmt(&conn);
  int iminid,imaxid;  
  // 准备删除数据的SQL,不需要判断返回值
  stmt.prepare("delete from goods where id>:1 and id<:2");
  // 为SQL语句绑定输入变量的地址
  stmt.bindin(1,&iminid);
  stmt.bindin(2,&imaxid);
  // 手工指定id的范围为1到5
  iminid=1;
  imaxid=5;
  
 //111111111111111111111111111111111111111111113.执行SQL语句,一定要判断返回值,0-成功,其它-失败
  if (stmt.execute() != 0)
  {
    printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
  }
  printf("本次从goods表中删除了%ld条记录。\n",stmt.m_cda.rpc); 
  conn.commit();
  return 0;
}

2.7 execplsql.cpp:执行一个PL/SQL过程

在这里插入图片描述

// execplsql.cpp:其中sql:删除全部记录并插入一行
// 在这里说一下我个人的意见,我从不在Oracle数据库中创建PL/SQL过程,也很少使用触发器,原因如下:
// 1、在Oracle数据库中创建PL/SQL过程,程序的调试很麻烦;
// 2、维护工作很麻烦,因为程序员要花时间去了解数据库中的存储过程;
// 3、在封装的oci中,对oracle的操作已经是简单的事情,没必要去折腾存储过程;
// 在oci中也很少用PL/SQL语句,也是因为复杂的PL/SQL调试麻烦。
#include "_ooci.h"

int main(int argc,char *argv[])
{
//111111111111111111111111111111111111111111111111.数据库连接池
  connection conn;  
  // 连接数据库,返回值0-成功,其它-失败
  // 失败代码在conn.m_cda.rc中,失败描述在conn.m_cda.message中。
  if (conn.connecttodb("scott/tiger@snorcl11g_138","Simplified Chinese_China.ZHS16GBK") != 0)
  {
    printf("connect database failed.\n%s\n",conn.m_cda.message); return -1;
  }
    
//111111111111111111111111111111111111111111111112.SQL语言操作类
  sqlstatement stmt(&conn);
  // 准备删除记录的PL/SQL,不需要判断返回值
  // 本PL/SQL先删除goods表中的全部记录,再插入一条记录
  stmt.prepare("\
    BEGIN\
      delete from goods;\
      insert into goods(id,name,sal,btime)\
                 values(:1,'过程商品',55.65,to_date('2018-01-02 13:00:55','yyyy-mm-dd hh24:mi:ss'));\
    END;");
  //上面2条sql语句,:1是为了绑定变量,:1换成100就没有下面两行了
  int id=100;
  stmt.bindin(1,&id);
  // 注意,PL/SQL中的每条SQL需要用分号结束,END之后还有一个分号。
  
//111111111111111111111111111111111111111111111113.执行SQL语句,一定要判断返回值,0-成功,其它-失败
  if (stmt.execute() != 0)
  {
    printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
  }
  printf("exec PL/SQL ok.\n");
  conn.commit();
  return 0;
}

3.虚表/日期/序列:ntp&hwclock

oracle的虚表dual用来构成select的语法规则,不要当表来看,oracle保证dual里永远只有一条记录,可用它来做如下很多事。
在这里插入图片描述
在这里插入图片描述
如下若是c语言写1/86400就是=0(因为整数除),只有浮点数才能这样运算。oracle中是非常精确的,不用担心精度问题。
在这里插入图片描述
如下sysdate函数返回值可以当成值来用。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
SQL>CREATE SEQUENCE ABC INCREMENT BY 1 START WITH 1 MAXVALUE 9999999999 NOCYCLE NOCACHE;
在这里插入图片描述
如上新建一个序列第一次取当前值是取不到的(提示该序列在此会话中未定义),必须.nextval再.currval取当前值。下面起步为100,步长为5。
在这里插入图片描述
下面给表增加两个字段crttime和keyid(导出数据时用到keyid),下面在crttable.sql中。
在这里插入图片描述
rowid指物理位置。rownum指序号(C语言很少用rownum)。如下第一行select时需要将rownum和rowid写出来查询才能看到,第二行用rowid作为查询或更新的条件最快(区别索引)
在这里插入图片描述
如上每条记录虽然存在数据库里(即表空间,表空间还是数据文件)最后还是存在磁盘上(在磁盘上就有位置),就是/oracle/base/oradata/snorcl11g里的.dbf文件。
在这里插入图片描述

4.索引/视图/链路/同义词:create index/view/link/synonym,distinct

在这里插入图片描述
ddatetime在数据库中是整数
在这里插入图片描述
视图就是访问数据的一个窗口,当成一个表来用,下面为先授权。
在这里插入图片描述
如上可以exit退出,也可直接切换connect scott用户,drop view …
在这里插入图片描述
在这里插入图片描述
视图不占用表空间,在emp将hiredate设置为系统时间,从v_emp查也有效果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面是同义词:数据库对象(表,视图,序列,存储过程,包)的一个别名。实际不可能给shqx和密码给客户,给普通用户如scott给客户并授权。
在这里插入图片描述
在这里插入图片描述
对表使用别名,如下内表是dept,外表是emp。
在这里插入图片描述
distinct关键字,取结果集中的唯一值,去重,如下有很多30,20,10重复。
在这里插入图片描述

5.系统高可用性:12个1T组合,rac

在这里插入图片描述
如下假如oracle数据库在一个服务器上运行,出问题了怎么办?(一般硬件故障)。Oracle三种高可用集群方案:1.RAC,2.Data Guard,3.OGG。如下是RAC技术,可以多个,但一般为两个。有的数据在内存,有的在缓存,2个要进行数据协调很麻烦,所以不是高性能,比单个服务器要慢。
在这里插入图片描述
如下为结合三种集群技术应用。
在这里插入图片描述
RAC有多个节点(上面为两个),应用程序只要做好客户端配置怎么连RAC数据库就行。
在这里插入图片描述

6.txt/xml文件入表:结构体内容

//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);
}
     
//11111111111111111111111111111111111111111111111处理入库
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/s
  int  r;              // 降雨量:0.1mm
  int  vis;            // 能见度:0.1米
};
struct st_signallog  //分区信号数据结构
{
  char obtid[11];
  char ddatetime[20];
  char signalname[2];
  char signalcolor[2];
};

//111111111111111111111111111111111111111111111111CSURFDATA类
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();
};

//1111111111111111111111111111111111111111111111CSIGNALLOG类
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表中。
};

//11111111111111111111111111111111111111111把非结构化数据文件写入oracle数据库的表中
int FileToTable(connection *in_conn,CLogFile *in_logfile,char *in_tname,char *in_filename,char *in_ddatetime);
#endif
//_shqx.cpp
#include "_shqx.h"
//11111111111111111111111111111111111111111111111111111CSURFDATA类
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/s
  CmdStr.GetValue(7,&dtmp); m_stsurfdata.r=(int)(dtmp*10);   // 降雨量:0.1mm
  CmdStr.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/s
  GetXMLBuffer(strBuffer,"r",&dtmp); m_stsurfdata.r=(int)(dtmp*10);   // 降雨量:0.1mm
  GetXMLBuffer(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;
}

//1111111111111111111111111111111111111111111111111111111111111CSIGNALLOG类
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); //数据时间:格式yyyymmddhh24mi
  strcat(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]就是A
    m_stsignallog.signalcolor[0]=strtemp[1]; //strtemp[1]就是3
    vsignallog.push_back(m_stsignallog);
    totalcount++;
  }
  return true;
}

long CSIGNALLOG::InsertTable()  //把vsignallog容器中的值更新到T_SIGNALDATA表中
{ //可能会返回stmtupt.m_cda.rc,所以用long
  if (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;
}

//11111111111111111111111111111111111111111111111把非结构化数据文件写入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-成功。  

//11111111111111111111111111111111111111111111111111111111111111111
  int 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;
  }    

//111111111111111111111111111111111111111111111111111111111111111
  stmt.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;
}

创建新用户并指定该用户缺省表空间为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;

下面是以超级用户登录,/ 指不用任何密码,不能远程登录只能登录本机且装有数据库。
在这里插入图片描述

7.站点参数建表入表/PowerDesigner/主外键:多表查询

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:勾上不允许为空。
在这里插入图片描述
1.下面为主键命名,主键在Columns里p字段已指定。
在这里插入图片描述
如下是主键的另一种写法。
在这里插入图片描述
2.下面为创建索引
在这里插入图片描述
在这里插入图片描述
3.下面为创建表空间,如下将表存入名为USERS的表空间。
在这里插入图片描述
如下将索引存入名为INDEXS表空间。
在这里插入图片描述
如下主键就是索引也有这些参数也扔入INDEXS表空间。
在这里插入图片描述
4.字段值附上约束条件,如果复制其他表记得删除字段值约束条件
在这里插入图片描述
5.如下U是unique index,记录序号即keyid是唯一约束,第三行是数据时间。
在这里插入图片描述
下面是创建序列。
在这里插入图片描述
ctrl+G生成.sql文件,注意主键名不要重复,双引号替换为空。复制刚生成的.sql文件内容到crttable.sql中,执行如下命令必须其他窗口SQL>exit。
在这里插入图片描述

8.数据交换:数据导出为文件,数据文件推送

在这里插入图片描述

// 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  
bool _xmltoarg(char *strxmlbuffer); // 把xml解析到参数starg结构中

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;
  }  
  if (_xmltoarg(argv[2])==false) return -1; // 把xml解析到参数starg结构中
  
  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);
}

//1111111111111111111111111111111111111111111111111111111111111111111111
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;
}

//111111111111111111111111111111111111111本程序的业务流程主函数
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);      
  if (stmt.execute() != 0)  // 执行导出数据的SQL
  {
    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");
    
//111111111111111111111111111111111111111111111111111111111111
    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);
    }
  }

//1111111111111111111111111111111111111111111111111111111111
  if (File.IsOpened()==true) //不够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);
  }
  if (stmt.m_cda.rpc>0) logfile.Write("本次导出了%d条记录。\n",stmt.m_cda.rpc);
  return true;
}

//1111111111111111111111111111111111111111111111111111
void SplitFields() //拆分fieldname和fieldlen
{
  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);
  }
}

//111111111111111111111111111111111从系统参数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;
}

//1111111111111111111111111111111111更新系统参数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条记录一个文件。
在这里插入图片描述
程序在后台跑,有新图就拿下来,wgetclient将网页内容全弄下来,搞清图片命名规律进行解析。

//wgetclient.cpp
#include "_public.h"
void EXIT(int sig);
CLogFile       logfile;
int main(int argc, char *argv[])
{
  if(argc!=6)
  {
    printf("Usage:%s weburl tmpfilename outputfilename logfilename charset\n",argv[0]); 
    printf("本程序用于获取WEB网页的内容。\n");
    printf("weburl 网页WEB的地址。\n");
    printf("tmpfilename 获取到的网页的内容存放的全路径的临时文件名,该文件可能是utf-8或其它编码。\n");
    printf("outputfilename 最终的输出文件全路径文件名,该文件是gb18030编码,注意tmpfilename被转换为outputfilename后,tmpfilename文件被自动删除。\n");
    printf("logfilename 本程序的运行产生的日志文件名。\n");
    printf("charset 网页的字符集,如utf-8\n\n");
    exit(1);
  }
  // 关闭全部的信号和输入输出
  // 设置信号,在shell状态下可用 "kill + 进程号" 正常终止些进程
  // 但请不要用 "kill -9 +进程号" 强行终止
  CloseIOAndSignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[4],"a+") == false)
  {
    printf("logfile.Open(%s) failed.\n",argv[4]); return -1;
  }

  MKDIR(argv[2],true); MKDIR(argv[3],true);
  char strweburl[3001];
  memset(strweburl,0,sizeof(strweburl));
  strncpy(strweburl,argv[1],3000);
 
  char strcmd[3024];
  memset(strcmd,0,sizeof(strcmd));
  snprintf(strcmd,3000,"/usr/bin/wget -c -q -O %s \"%s\" 1>>/dev/null 2>>/dev/null",argv[2],strweburl);
  system(strcmd);
  logfile.Write("%s\n",strcmd);

  char strfilenametmp[301];
  memset(strfilenametmp,0,sizeof(strfilenametmp));
  snprintf(strfilenametmp,300,"%s.tmp",argv[3]);

   // 把获取到的网页转换为中文
  memset(strcmd,0,sizeof(strcmd));
  snprintf(strcmd,256,"iconv -c -f %s -t gb18030 %s -o %s",argv[5],argv[2],strfilenametmp);
  system(strcmd);
  logfile.Write("%s\n",strcmd);
  REMOVE(argv[2]);   // 删除临时文件 
  RENAME(strfilenametmp,argv[3]);
  return 0;
}

void EXIT(int sig)
{
  if (sig > 0) signal(sig,SIG_IGN);
  logfile.Write("catching the signal(%d).\n",sig);
  logfile.Write("wgetclient exit.\n");
  exit(0);
}

在这里插入图片描述

//wgetrain24.cpp
#include "_public.h"
void EXIT(int sig);
CLogFile       logfile;
bool GetURL(char *strBuffer,char *strURL,char *strFileName);
int main(int argc, char *argv[])
{
  if(argc!=4)
  {
    printf("Usage:%s logfilename tmpfilename outputfilename\n",argv[0]); 
    printf("Sample:./wgetrain24 /log/shqx/wgetrain24.log /data/wgettmp /data/wfile/zhrain24\n\n");
    printf("本程序用于从中国天气网获取逐小时降雨量实况图。\n");
    printf("中国天气网的url是http://products.weather.com.cn/product/Index/index/procode/JC_JSL_ZH.shtml\n");
    printf("如果中国天气网的url改变,程序也在做改动。\n");
    printf("logfilename 本程序的运行产生的日志文件名。\n");
    printf("tmpfilename 本程序运行产生的临时文件存放的目录。\n");
    printf("获取逐小时降雨量实况图存放的目录。\n\n");
    exit(1);
  }
  CloseIOAndSignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[1],"a+") == false)
  {
    printf("logfile.Open(%s) failed.\n",argv[1]); return -1;
  }

  MKDIR(argv[2],false); MKDIR(argv[3],false);
  while (true)
  {    
    char strwgetclient[2001];  // 调用wgetclient获取网页内容
    memset(strwgetclient,0,sizeof(strwgetclient));
    snprintf(strwgetclient,2000,"/htidc/public/bin/wgetclient \"http://products.weather.com.cn/product/Index/index/procode/JC_JSL_ZH.shtml\" %s/wgetclient_%d.tmp  %s/wgetclient_%d.html %s/wgetclient.log utf-8",argv[2],getpid(),argv[2],getpid(),argv[2]);
    system(strwgetclient);
    // logfile.Write("%s\n",strwgetclient);
  
    // 打开网页内容文件
    char stroutputfile[301];
    memset(stroutputfile,0,sizeof(stroutputfile));
    snprintf(stroutputfile,300,"%s/wgetclient_%d.html",argv[2],getpid());
    CFile File;
    if (File.Open(stroutputfile,"r")==false)
    {
      logfile.Write("File.Open(%s) failed.\n",stroutputfile); sleep(60); continue;
    }    
    char strBuffer[1001],strURL[501],strFullFileName[301],strFileName[101];  
   
    // 得到全部的图片文件名
    while (true)
    {
      memset(strBuffer,0,sizeof(strBuffer));
      memset(strURL,0,sizeof(strURL));
      memset(strFullFileName,0,sizeof(strFullFileName));
      memset(strFileName,0,sizeof(strFileName));  
      if (File.Fgets(strBuffer,1000)==false) break;  
      if (MatchFileName(strBuffer,"*PWCP_TWC_WEAP_SFER_ER1_TWC_L88_P9_20*.JPG*")==false) continue;  
      // logfile.Write("%s",strBuffer);        
      if (GetURL(strBuffer,strURL,strFileName)==false) continue; //解析出url和文件名       
      snprintf(strFullFileName,300,"%s/%s",argv[3],strFileName); //文件已存在,不采集
      if (access(strFullFileName,F_OK)==0) continue;  
      
      logfile.Write("download %s ",strFileName); //调用wget获取文件
      memset(strwgetclient,0,sizeof(strwgetclient));
      snprintf(strwgetclient,500,"wget \"%s\" -o %s/wgetrain24.log -O %s",strURL,argv[2],strFullFileName);
      system(strwgetclient);  
      if (access(strFullFileName,F_OK)==0) logfile.WriteEx("ok.\n");
      else logfile.WriteEx("failed.\n");
    }  
    File.CloseAndRemove();
    sleep(60);
  }
  return 0;
}

bool GetURL(char *strBuffer,char *strURL,char *strFileName)
{
  char *start,*end;
  start=end=0;
  if ((start=strstr(strBuffer,"http"))==0) return false;
  if ((end=strstr(start,"\""))==0) return false; //找双引号
  strncpy(strURL,start,end-start);
  strcpy(strFileName,strstr(strURL,"PWCP"));
  return true;
}
void EXIT(int sig)
{
  if (sig > 0) signal(sig,SIG_IGN);
  logfile.Write("catching the signal(%d).\n",sig);
  logfile.Write("wgetclient exit.\n");
  exit(0);
}

在这里插入图片描述

9.非结构化数据存储:blob,pzhrain24file

在这里插入图片描述

// 本程序演示如何把磁盘文件的文本文件写入Oracle的BLOB字段中。
//filetoblob.cpp,实时生成的不要存oracle的blob字段
#include "_ooci.h"
int main(int argc,char *argv[])
{
  connection conn;  
  // 连接数据库,返回值0-成功,其它-失败
  // 失败代码在conn.m_cda.rc中,失败描述在conn.m_cda.message中。
  if (conn.connecttodb("scott/tiger@snorcl11g_198","Simplified Chinese_China.ZHS16GBK") != 0)
  {
    printf("connect database %s failed.\n%s\n","scott/tiger@orcl",conn.m_cda.message); return -1;
  }    
  sqlstatement stmt(&conn);  // SQL语言操作类 
  // 为了方便演示,把goods表中的记录全删掉,再插入一条用于测试的数据。
  // 不需要判断返回值
  stmt.prepare("\
    BEGIN\
      delete from goods;\
      insert into goods(id,name,pic) values(1,'商品名称',empty_blob());\
    END;");  
  // 执行SQL语句,一定要判断返回值,0-成功,其它-失败。
  if (stmt.execute() != 0)
  {
    printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
  }
  // 使用游标从goods表中提取id为1的pic字段
  // 注意了,同一个sqlstatement可以多次使用
  // 但是,如果它的sql改变了,就要重新prepare和bindin或bindout变量
  stmt.prepare("select pic from goods where id=1 for update");
  stmt.bindblob();
  // 执行SQL语句,一定要判断返回值,0-成功,其它-失败。
  if (stmt.execute() != 0)
  {
    printf("stmt.execute() failed.\n%s\n%s\n",stmt.m_sql,stmt.m_cda.message); return -1;
  }
  // 获取一条记录,一定要判断返回值,0-成功,1403-无记录,其它-失败。
  if (stmt.next() != 0) return 0;  
  // 把磁盘文件pic_in.jpg的内容写入BLOB字段,一定要判断返回值,0-成功,其它-失败。
  if (stmt.filetolob((char *)"pic_in.jpg") != 0)
  {
    printf("stmt.filetolob() failed.\n%s\n",stmt.m_cda.message); return -1;
  }  
  conn.commit(); // 提交事务
  return 0;
}

在这里插入图片描述
如下文件信息放入表中。
在这里插入图片描述

// pzhrain24file.cpp
#include "_public.h"
#include "_ooci.h"
#include "_shqx.h"
CLogFile logfile;
CDir Dir;
// 处理数据文件
bool _pzhrain24file(char *strargv2,char *strargv4,char *strargv5);
connection conn;
void EXIT(int sig);

int main(int argc,char *argv[])
{
  if (argc!=7)
  {
    printf("\n本程序用于处理全国逐小时雨量实况图片文件。\n\n");
    printf("/htidc/shqx/bin/pzhrain24file logfilename connstr srcpathname dstpathname tname timetvl\n");
    printf("例如:/htidc/shqx/bin/pzhrain24file /log/shqx/pzhrain24file.log shqx/pwdidc@snorcl11g_198 /data/wfile/zhrain24 /qxfile/zhrain24 T_ZHRAIN24 30\n");
    printf("logfilename 本程序运行的日志文件名。\n");
    printf("connstr 数据库的连接参数。\n");
    printf("srcpathname 原始文件存放的目录,文件命名如PWCP_TWC_WEAP_SFER_ER1_TWC_L88_P9_20191101070000000.JPG。\n");
    printf("dstpathname 目标文件存放的目录,文件按yyyy/mm/dd组织目录,重命名为zhrain24_yyyymmddhh24miss.jpg。\n");
    printf("tname 数据存放的表名。\n");
    printf("timetvl 本程序运行的时间间隔,单位:秒。\n");
    return -1;
  }
  CloseIOAndSignal();
  signal(SIGINT,EXIT); signal(SIGTERM,EXIT);

  if (logfile.Open(argv[1],"a+")==false)
  {
    printf("打开日志文件失败(%s)。\n",argv[1]); return -1;
  }
  logfile.Write("程序启动。\n");
  while (true)
  {
    // logfile.Write("开始扫描目录。\n");
    // 扫描数据文件存放的目录,只匹配"PWCP_TWC_WEAP_SFER_ER1_TWC_L88_P9_20*.JPG"
    if (Dir.OpenDir(argv[3],"PWCP_TWC_WEAP_SFER_ER1_TWC_L88_P9_20*.JPG",1000,true,true)==false)
    {
      logfile.Write("Dir.OpenDir(%s) failed.\n",argv[3]); sleep(atoi(argv[6])); continue;
    }    
    while (true) // 逐个处理目录中的数据文件
    {
      if (Dir.ReadDir()==false) break;
      if (_pzhrain24file(argv[2],argv[4],argv[5])==false) 
      {
        logfile.WriteEx("失败。\n"); continue;
      }
    }
    if (conn.m_state==1) conn.disconnect(); 
    sleep(atoi(argv[6]));
  }
  return 0;
}
void EXIT(int sig)
{
  logfile.Write("程序退出,sig=%d\n\n",sig);
  exit(0);
}

//1111111111111111111111111111111111111111111处理数据文件
bool _pzhrain24file(char *strargv2,char *strargv4,char *strargv5)
{
  char strddatetime[21];   // 文件的数据时间,格式yyyymmddhh24miss
  memset(strddatetime,0,sizeof(strddatetime));
  strncpy(strddatetime,strstr(Dir.m_FileName,"20"),14);
  
  //搜索文件名PWCP_TWC…中20,后面取14位,重命名为zhrain24_%s.jpg
  char strdstfilename[301];  // 目标文件名,不带路径
  memset(strdstfilename,0,sizeof(strdstfilename));
  snprintf(strdstfilename,300,"zhrain24_%s.jpg",strddatetime);
  
  char strdstfilepath[301];  // 目标文件存放的目录
  memset(strdstfilepath,0,sizeof(strdstfilepath));
  snprintf(strdstfilepath,300,"%s/",strargv4);
  strncat(strdstfilepath,strddatetime,4);     strcat(strdstfilepath,"/");  // 年的子目录
  strncat(strdstfilepath,strddatetime+4,2);   strcat(strdstfilepath,"/");  // 月的子目录
  strncat(strdstfilepath,strddatetime+6,2);   strcat(strdstfilepath,"/");  // 日的子目录

  char strfulldstfilename[301]; // 目标文件名,全路径
  memset(strfulldstfilename,0,sizeof(strfulldstfilename));
  snprintf(strfulldstfilename,300,"%s%s",strdstfilepath,strdstfilename);

  // 如果文件已处理(目标文件已存在),直接返回成功。
  if (access(strfulldstfilename,F_OK) == 0) return true;

  if (conn.m_state==0)
  {
    if (conn.connecttodb(strargv2,"Simplified Chinese_China.ZHS16GBK")!=0)
    {
      logfile.Write("connect database(%s) failed.\n%s\n",strargv2,conn.m_cda.message); return false;
    }
    // logfile.Write("连接数据库成功。\n");
  }
  
  // 把源文件复制到目标文件
  if (COPY(Dir.m_FullFileName,strfulldstfilename)==false) 
  {
    logfile.Write("复制文件COPY(%s,%s)...failed.\n",Dir.m_FullFileName,strfulldstfilename); return false;
  }

  // 把非结构化数据文件写入oracle数据库的表中
  if (FileToTable(&conn,&logfile,strargv5,strfulldstfilename,strddatetime)!=0)
  {
    logfile.Write("把文件%s存入%s...failed.\n",strfulldstfilename,strargv5);  return false;
  }
  logfile.Write("把文件%s存入%s...ok.\n",strfulldstfilename,strargv5);  
  return true;
}

在这里插入图片描述
在这里插入图片描述

10.磁盘/cpu信息收集:内存信息free -m,和top命令查看的内存是一样的,也在系统文件/proc/meminfo

在这里插入图片描述

//diskinfo.cpp,写入xml文件中再入库
#include "_public.h"
void EXIT(int sig);
CLogFile logfile;

int main(int argc,char *argv[])
{
  if (argc != 4)
  {
    printf("\n");
    printf("Using:./diskinfo hostname logfilename outputpath\n");

    printf("Example:/htidc/public/bin/diskinfo 118.89.50.198 /tmp/htidc/log/diskinfo.log /tmp/htidc/monclient\n\n");
    printf("此程序调用df命名,把本服务器的磁盘使用率信息写入xml文件。\n");
    printf("hostname是本服务器的主机名,为了方便识别,也可以用IP。\n");
    printf("logfilename是本程序的日志文件名。\n");
    printf("outputpath是输出的xml文件存放的目录。\n");
    printf("此程序运行在需要监控的服务器上(本程序只适用Linux系统),采集后的xml文件由文件传输程序发送给数据处理服务程序入库。\n\n\n");

    return -1;
  }
  CloseIOAndSignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[2],"a+") == false)
  {
    printf("logfile.Open(%s) failed.\n",argv[2]); return -1;
  }

  FILE *fp=0;
  if ( (fp=popen("df -k --block-size=1M","r")) == NULL )
  {
    logfile.Write("popen(df -k --block-size=1M) failed.\n"); return false;
  }

  char strXMLFileName[301],strLocalTime[21];
  memset(strXMLFileName,0,sizeof(strXMLFileName));
  memset(strLocalTime,0,sizeof(strLocalTime));
  LocalTime(strLocalTime,"yyyymmddhh24miss");
  snprintf(strXMLFileName,300,"%s/diskinfo_%s_%s.xml",argv[3],strLocalTime,argv[1]);

  CFile XMLFile;
  if (XMLFile.OpenForRename(strXMLFileName,"w+") == false )
  {
    logfile.Write("XMLFile.OpenForRename(%s) failed.\n",strXMLFileName); pclose(fp); return -1;
  }

  XMLFile.Fprintf("<data>\n");

  CCmdStr CmdStr;
  char strBuffer[1024],strLine[500];
  
  while (true)
  {
    memset(strBuffer,0,sizeof(strBuffer));
    if (FGETS(fp,strBuffer,500) == false) break;
    // 如果没有找到“%”,就再读取一行,与strBuffer拼起来
    if (strstr(strBuffer,"%") == 0)
    {
      memset(strLine,0,sizeof(strLine));
      if (FGETS(fp,strLine,500) == false) break;
      strcat(strBuffer," "); strcat(strBuffer,strLine);
    }
    // 删除字符串前后的空格和换行符
    DeleteLRChar(strBuffer,' '); DeleteLRChar(strBuffer,'\n');
    // 把字符串中间的多个空格全部转换为一个空格
    UpdateStr(strBuffer,"  "," ");
    // 把全内容全部转换为小写
    ToLower(strBuffer);
    // 除了磁盘信息,还有可能是内存,SMB等其它文件,都丢弃掉
    if (strncmp(strBuffer,"/dev",4) != 0) continue;

    CmdStr.SplitToCmd(strBuffer," ");
    if (CmdStr.CmdCount() != 6) continue;

    char strusep[21];
    memset(strusep,0,sizeof(strusep));
    strcpy(strusep,CmdStr.m_vCmdStr[4].c_str());
    UpdateStr(strusep,"%","");

    char strLocalTime[21];
    memset(strLocalTime,0,sizeof(strLocalTime));
    LocalTime(strLocalTime,"yyyymmddhh24miss");
    XMLFile.Fprintf(\
            "<nodip>%s</nodip>"\
            "<crttime>%s</crttime>"\
            "<filesystem>%s</filesystem>"\
            "<total>%0.02f</total>"\
            "<used>%0.02f</used>"\
            "<available>%0.02f</available>"\
            "<usep>%0.02f</usep>"\
            "<mount>%s</mount><endl/>\n",
             argv[1],
             strLocalTime,
             CmdStr.m_vCmdStr[0].c_str(),
             atof(CmdStr.m_vCmdStr[1].c_str())/1024.0,
             atof(CmdStr.m_vCmdStr[2].c_str())/1024.0,
             atof(CmdStr.m_vCmdStr[3].c_str())/1024.0,
             (atof(CmdStr.m_vCmdStr[2].c_str())/atof(CmdStr.m_vCmdStr[1].c_str()))*100.0,
             CmdStr.m_vCmdStr[5].c_str());
  }
  XMLFile.Fprintf("</data>\n");
  pclose(fp);
  XMLFile.CloseAndRename();
  logfile.Write("create %s ok.\n",strXMLFileName);
  exit(0);
}

void EXIT(int sig)
{
  if (sig > 0) signal(sig,SIG_IGN);
  logfile.Write("catching the signal(%d).\n",sig);
  logfile.Write("diskinfo exit.\n");
  exit(0);
}

cpuinfo.cpp思路是定义三个结构体变量,加载cpu信息到结构体里,睡60s,再继续加载cpu信息到结构体里,再将两结构体成员相减,就可以知道一分钟内cpu情况,采用的是一分钟信息。vi /proc/stat如下。
在这里插入图片描述

//cpuinfo.cpp
#include "_public.h"
void EXIT(int sig);
CLogFile logfile;
struct st_cpuinfo
{
  double user;
  double sys;
  double wait;
  double nice;
  double idle;
  double irq;
  double softirq;
  double total;
};
struct st_cpuinfo stcpuinfo1,stcpuinfo2,stcpuinfo3;
bool LoadCPUInfo(struct st_cpuinfo &stcpuinfo);

int main(int argc,char *argv[])
{
  if (argc != 4)
  {
    printf("\n");
    printf("Using:./cpuinfo hostname logfilename outputpath\n");
    printf("Example:/htidc/public/bin/cpuinfo 118.89.50.198 /tmp/htidc/log/cpuinfo.log /tmp/htidc/monclient\n\n");

    printf("此程序读取/proc/stat文件,把本服务器的CPU使用率信息写入xml文件。\n");
    printf("hostname是本服务器的主机名,为了方便识别,也可以用IP。\n");
    printf("logfilename是本程序的日志文件名。\n");
    printf("outputpath是输出的xml文件存放的目录。\n");
    printf("此程序运行在需要监控的服务器上(本程序只适用Linux系统),采集后的xml文件由文件传输程序发送给数据处理服务程序入库。\n\n\n");
 
    return -1;
  }
  //memset(strHostName,0,sizeof(strHostName));
  //strncpy(strHostName,argv[2],20);
  CloseIOAndSignal(); signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[2],"a+") == false)
  {
    printf("logfile.Open(%s) failed.\n",argv[2]); return -1;
  }
  memset(&stcpuinfo1,0,sizeof(struct st_cpuinfo));
  memset(&stcpuinfo2,0,sizeof(struct st_cpuinfo));
  memset(&stcpuinfo3,0,sizeof(struct st_cpuinfo));

  if (LoadCPUInfo(stcpuinfo1) ==false) return -1;  
  sleep(60);
  if (LoadCPUInfo(stcpuinfo2) ==false) return -1;

  stcpuinfo3.user=stcpuinfo2.user-stcpuinfo1.user;
  stcpuinfo3.sys=stcpuinfo2.sys-stcpuinfo1.sys;
  stcpuinfo3.wait=stcpuinfo2.wait-stcpuinfo1.wait;
  stcpuinfo3.nice=stcpuinfo2.nice-stcpuinfo1.nice;
  stcpuinfo3.idle=stcpuinfo2.idle-stcpuinfo1.idle;
  stcpuinfo3.irq=stcpuinfo2.irq-stcpuinfo1.irq;
  stcpuinfo3.softirq=stcpuinfo2.softirq-stcpuinfo1.softirq;
  stcpuinfo3.total=stcpuinfo3.user+stcpuinfo3.sys+stcpuinfo3.wait+stcpuinfo3.nice+stcpuinfo3.idle+stcpuinfo3.irq+stcpuinfo3.softirq;

  char strLocalTime[21];
  memset(strLocalTime,0,sizeof(strLocalTime));
  LocalTime(strLocalTime,"yyyymmddhh24miss");

  char strXMLFileName[301];
  memset(strXMLFileName,0,sizeof(strXMLFileName));
  snprintf(strXMLFileName,300,"%s/cpuinfo_%s_%s.xml",argv[3],strLocalTime,argv[1]);

  CFile XMLFile;
  if (XMLFile.OpenForRename(strXMLFileName,"w+") == false )
  {
    logfile.Write("XMLFile.OpenForRename(%s) failed.\n",strXMLFileName); return -1;
  }
  XMLFile.Fprintf("<data>\n");

  XMLFile.Fprintf("<nodip>%s</nodip><crttime>%s</crttime><user>%0.02f</user><sys>%0.02f</sys><wait>%0.02f</wait><nice>%0.02f</nice><idle>%0.02f</idle><usep>%0.02f</usep><endl/>\n",argv[1],strLocalTime,stcpuinfo3.user/stcpuinfo3.total*100.0,stcpuinfo3.sys/stcpuinfo3.total*100.0,stcpuinfo3.wait/stcpuinfo3.total*100.0,stcpuinfo3.nice/stcpuinfo3.total*100.0,stcpuinfo3.idle/stcpuinfo3.total*100.0,100.0-stcpuinfo3.nice/stcpuinfo3.total*100.0);

  XMLFile.Fprintf("</data>\n");
  XMLFile.CloseAndRename();
  logfile.Write("create %s ok.\n",strXMLFileName);
  exit(0);
}
void EXIT(int sig)
{
  if (sig > 0) signal(sig,SIG_IGN);
  logfile.Write("catching the signal(%d).\n",sig);
  logfile.Write("cpuinfo exit.\n");
  exit(0);
}

bool LoadCPUInfo(struct st_cpuinfo &stcpuinfo)
{
  CFile CPUFile;
  if (CPUFile.Open("/proc/stat","r") == false )
  {
    logfile.Write("CPUFile.OpenForRead(/proc/stat) failed.\n"); return false;
  }
  CCmdStr CmdStr;
  char strBuffer[1024];
  while (true)
  {
    memset(strBuffer,0,sizeof(strBuffer));
    if (CPUFile.FFGETS(strBuffer,500) == false) break;
    // 删除字符串前后的空格
    DeleteLRChar(strBuffer,' ');
    // 把字符串中间的多个空格全部转换为一个空格
    UpdateStr(strBuffer,"  "," ");
    ToLower(strBuffer);
    CmdStr.SplitToCmd(strBuffer," ");
    if (strcmp(CmdStr.m_vCmdStr[0].c_str(),"cpu")==0) 
    {
      stcpuinfo.user=atof(CmdStr.m_vCmdStr[1].c_str());
      stcpuinfo.sys=atof(CmdStr.m_vCmdStr[2].c_str());
      stcpuinfo.wait=atof(CmdStr.m_vCmdStr[3].c_str());
      stcpuinfo.nice=atof(CmdStr.m_vCmdStr[4].c_str());
      stcpuinfo.idle=atof(CmdStr.m_vCmdStr[5].c_str());
      stcpuinfo.irq=atof(CmdStr.m_vCmdStr[6].c_str());
      stcpuinfo.softirq=atof(CmdStr.m_vCmdStr[7].c_str());
      return true;
    }
  }
  logfile.Write("Read /proc/stat failed.\n"); 
  return false;
}

在这里插入图片描述
vi /tmp/htdic/monclient/cpu*,如下是收集到的信息。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/736469.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Selenium进行Web自动化测试

Selenium进行Web自动化测试 SeleniumPython实现Web自动化测试一、环境配置 SeleniumPython实现Web自动化测试 一、环境配置 环境基于win10&#xff08;X64&#xff09; 安装Python&#xff1b;安装PyCham安装chomedriver chomedriver下载地址 可以查看本地chrome软件版本下载…

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【13】压力压测JMeter-性能监控jvisualvm

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【13】压力压测JMeter-性能监控jvisualvm 压力测试概述性能指标 JMeter基本使用添加线程组添加 HTTP 请求添加监听器启动压测&查看分析结果JMeter Address Already in use 错误解决 性…

电子电气架构——由NRC优先级引起的反思

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

matplotlib之savefig函数

savefig函数 Matplotlib中&#xff0c;savefig函数用于保存图形为文件。通过该函数&#xff0c;你可以将绘制的图形保存为常见的图像文件格式&#xff0c;如PNG、JPEG、SVG等。 matplotlib.pyplot.savefig(fname, dpiNone, bbox_inchestight, pad_inches0.1, formatNone, tra…

C++封装、继承、多态的应用---职工管理系统

C封装、继承、多态的应用—职工管理系统 文章目录 C封装、继承、多态的应用---职工管理系统1.需求分析2.抽象类的建立2.1抽象基类2.2员工类2.3经理类2.4老板类2.5存储类 3.抽象类的实现4.功能函数的实现4.1菜单功能的实现4.2增加职工功能函数实现4.2显示职工功能函数实现4.3删除…

初中英语优秀作文分析-005How to Plan Our Life Wisely-如何明智地规划我们的生活

PDF格式公众号回复关键字:SHCZYF005 记忆树 1 The “double reduction policy” reduces the burden on students and offers us more spare time than before, but how to plan our life wisely? 翻译 “双减政策”减轻了学生的负担&#xff0c;给了我们比以前更多的业余…

DVWA-XSS(Stored)-beef

用Low Level来测试beef的使用 beef配置 如果kali没有beef的&#xff0c;进行下载 apt install beef-xss使用 beef-xss # 命令方式启动 beef-xss-stop # 命令方式关闭 systemctl start beef-xss.service #开启beefsystemctl stop beef-xss.service #关闭…

充电学习—1、psy框架梳理

一、linux充电驱动代码框架&#xff1a; APP 层 该部分属于电量上报的最后的环节。其主要工作是&#xff1a;监听系统广播并对 UI 作出相应更新&#xff0c;包括电池电量百分比&#xff0c;充电状态&#xff0c;低电提醒&#xff0c;led 指示灯&#xff0c;异常提醒等FrameWork…

【pytorch06】 维度变换

常用API view/reshapesqueeze/unsqueezetranspose/t/permuteexpand/repeat view和reshape view操作的基本前提是保证numel()一致 a.view(4,28*28)的物理意义是把行宽以及通道合并在一起&#xff0c;对于4张图片&#xff0c;我们直接把所有数据都合在一起&#xff0c;用一个7…

详解 Macvlan 创建不同容器独立跑仿真(持续更新中)

一、概念介绍 1.1 什么是macvlan macvlan是一种网卡虚拟化技术&#xff0c;能够将一张网卡&#xff08;Network Interface Card, NIC&#xff09;虚拟出多张网卡&#xff0c;这意味着每个虚拟网卡都能拥有独立的MAC地址和IP地址&#xff0c;从而在系统层面表现为完全独立的网络…

MySQL命名规范(自用)

MtySQL命名规范 基本通用规范 1.【推荐】关键字必须大写 所有关键字必须大写&#xff0c;如&#xff1a;INSERT、UPDATE、DELETE、SELECT及其子句&#xff0c;IF……ELSE、CASE、DECLARE等 2.【强制】字段和建表必须写备注 COMMENT写备注 3.【强制】字母数字下划线 采用26个英…

AIGC系列之一-一文理解什么是Embedding嵌入技术

摘要&#xff1a;嵌入技术&#xff08;Embedding&#xff09;是一种将高维数据映射到低维空间的技术&#xff0c;在人工智能与图形学研究中被广泛应用。本文将介绍嵌入技术的基本概念、原理以及在 AIGC&#xff08;Artificial Intelligence and Graphics Computing&#xff09;…

PAL: Program-aided Language Models

PAL: Program-aided Language Models ArXiv&#xff1a;https://arxiv.org/pdf/2211.10435 GitHub&#xff1a;https://reasonwithpal.com/ 一、动机 大模型与Chain-of-Thought可以很好地将一些复杂的问题分解为若干个子问题并进行逐步推理&#xff1b;但是对于一些较为复杂…

个人成长的利器:复盘教你如何避免重蹈覆辙

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热爱技术和分享&#xff0c;欢迎大家交流&#xff0c;一起学习进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 最近忙着学习和工作&#xff0c;更新比较少&#xff0c;期间一直在思考如何才能快速…

区块链技术原理

1.起源&#xff1a; ➢ 中本聪(Satoshi Nakamoto), 2008 ➢ 比特币:一种点对点的电子现金系统 2.分布式账本技术原理 ➢ 将交易向全网所有节点进行广播 ➢ 众多记账节点对记账权达成共识&#xff0c;由共识确认的记账节点把记账区块发布给全网 ➢ 所有账本数据完整存储于区块…

【Linux】进程间通信_1

文章目录 七、进程间通信1. 进程间通信分类管道 未完待续 七、进程间通信 进程间由于 进程具有独立性 &#xff0c;所以不可以直接进行数据传递。但是我们通常需要多个进程协同&#xff0c;共同完成一件事&#xff0c;所以我们需要进程间通信的手段。进程间通信的本质就是先让…

AI 开发平台(Coze)搭建小游戏《挑战花光10亿》

前言 本文讲解如何从零开始&#xff0c;使用扣子平台去搭建一个小游戏 这是成品链接&#xff1a;挑战花光10亿 - 扣子 AI Bot (coze.cn) 欢迎大家去体验一下 效果 正文 什么是coze平台&#xff1f; 扣子&#xff08;Coze&#xff09;是字节跳动推出的一站式 AI 开发平台&am…

osi七层参考模型和tcp/ip模型的区别与相似之处

osi七层参考模型&#xff1a; 2.tcp/ip四层参考模型&#xff1a; osi七层参考模型与tcp/ip四层参考模型的相似与区别&#xff1a; 相同点&#xff1a; 2者都是模型化层次化 下层对上层提供服务支持 每层协议彼此相互独立 不同点&#xff1a;OSI先有模型才有协议 TCP/IP先有…

DS:二叉树的链式存储及遍历

​ 欢迎来到Harper.Lee的学习世界&#xff01; 博主主页传送门&#xff1a;Harper.Lee的博客主页 想要一起进步的uu可以来后台找我哦&#xff01; ​ 一、引入 1.1 二叉树的存储方式 在之前接触到的满二叉树和完全二叉树使用的是数组的存储方式&#xff08;DS&#xff1a;树与…

Python编程技巧:如何正确使用with语句(Python中with用法详解)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 基本语法📝 处理文件📝 处理网络连接📝 管理线程锁📝 管理数据库连接📝 管理临时目录和文件📝 使用上下文装饰器📝 自定义上下文管理器🎯 示例1🎯 示例2📝 使用多个上下文管理器📝 上下…