【C++3】crontab,ftp

news2024/11/16 11:51:40

文章目录

  • 1.生成数据:crontab
  • 2.ftp:ftp是tcp/ip协议族中一员,分客户端和服务端
    • 2.1 安装:linux操作系统的用户也是ftp的用户,可以配置专用的ftp用户,专用的ftp用户只能用于ftp,不能登录操作系统
    • 2.2 ftp命令:get,put
      • 登录ftp服务器:linux命令行输入:ftp ip地址,然后输入用户名和密码(adduser ,passwd ),必须先开启ftp服务
      • 查看/下载/上传文件:ftp的传输模式分ASCII码和二进制两种,二进制可传输任何文件,而ASCII码方式只能传输.txt、.html,实际开发中,不管什么文件都用二进制传输文件省事
    • 2.3 ftp应用:OpenForRename,Fgets
      • 数据完整性:在一文件夹里 ls | wc 统计数据行数
      • C语言实现ftp下载文件:.a就是静态库相当.c/.cpp一个别名,编译时不让人看见,makefile中libftp.a就是ftplib.c。


1.生成数据:crontab

https://pan.baidu.com/s/1QL5TK3mcowVjCIPPCdhstw,提取码:0p53。
在这里插入图片描述
打开文件一行一行读出来,字符拆分存入结构体再存入容器:mkdir src bin ini data,data/ftp/surfdata/,cd src/,vi makefile如下。

// 记住复制时第一行完整CC,一个tab缩进。crtsurfdata:crtsurfdata.cpp _public.h _public.cpp即 _public.h _public.cpp改变也要重新编译。
CC=g++
FLAG=-g
#FLAG=-02

all:crtsurfdata
crtsurfdata:crtsurfdata.cpp _public.h _public.cpp
        $(CC) $(FLAG) -o crtsurfdata crtsurfdata.cpp _public.cpp
        cp crtsurfdata ../bin/.
clean:
        rm -rf crtsurfdata

在这里插入图片描述
日志切换怎么做的:先把日志文件关闭,生成日志备份的文件名再rename,重新打开新的日志文件。 在多进程中不能采用日志切换的方法,在某一个进程中关闭指针文件,其他就全部关了不会再打开。
在这里插入图片描述
如果2秒这样执行很频繁的话,自身调度没问题,但像60s一分钟执行一次(运行一次1秒都不到就过去了),挂着一分钟会常驻内存浪费系统资源。所以用linux中crontab,每个用户都有自己的crontab任务调度。
在这里插入图片描述
cron(特定时间点执行shell指令)是unix下自带的工具,伴随着系统的启动,是一个守护进程。如下是cron表达式,后面接空格再加上要执行的shell脚本。
在这里插入图片描述
如下每星期每月每日每小时的第20分钟到第40分钟每分钟都会执行一次(1小时执行21次)。
在这里插入图片描述
在这里插入图片描述
crontab -e进入如下,dow表示星期。
在这里插入图片描述
如下是crtsurfdata.cpp生成全国气象站点观测的分钟数据:结构体值,容器值,txt文件。

#include "_public.h" // 安徽,58102,亳州,33.47,115.44,39.1,_public.h同目录
// 全国气象 (站点参数stcode) 数据结构
struct st_stcode
{
  char provname[31];   // 省名称
  char obtid[11];      // 站点代码 //也可能是字母所以用字符串表达
  char cityname[31];   // 城市名
  double lat;          // 纬度
  double lon;          // 经度
  double height;       // 海拔高度
};
// 全国气象站点分钟 (生成的观测数据surfdata) 数据结构
struct st_surfdata
{
  char obtid[11];      // 站点代码
  char ddatetime[21];  // 数据时间:格式yyyy-mm-dd hh24: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米
}; 
vector<struct st_stcode> vstcode;   // 存放全国站点参数的容器  //将结构体放入容器中,就直接操作容器了
vector<struct st_surfdata> vsurfdata;   // 存放全国气象站点分钟观测数据的容器
// 从站点参数文件中加载到vstcode容器中,在函数里字符串只能传地址
bool LoadSTCode(const char *inifile);
// 创建全国气象站点分钟观测数据,存放在vsurfdata容器中
void CrtSurfData();
// 把容器vsurfdata中的全国气象站点分钟观测数据写入文件
bool CrtSurfFile(const char *outpath);
CLogFile logfile;
void EXIT(int sig);

int main(int argc,char *argv[],char *envp[])    //*argv[]:指针的数组,也可以**argv指针的指针
{  
  if (argc!=4)
  {  
    printf("\n本程序用于生成全国气象站点观测的分钟数据。\n");
    printf("/root/qxidc/bin/crtsurfdata 站点参数 数据文件存放的目录 日志文件名\n");
    printf("例如:/root/qxidc/bin/crtsurfdata /root/qxidc/ini/stcode.ini /root/qxidc/data/ftp/surfdata /root/qxidc/log/crtsurfdata.log\n");  //目录自动创建
    return -1;  //程序没有捕获运行结果,所以0,-1无所谓,return -1失败跳出大循环,return 0成功
  }
  // 关闭全部输入输出和信号,也可写成void CloseIOAndSignal(); 下面printf失效
  CloseIOAndSignal();
  // 因为程序运行需要退出,所以捕获退出信号(ctrl+c或kill/kill all),signal将这两个信号值作为sig参数传给EXIT函数
  signal(SIGINT,EXIT); signal(SIGTERM,EXIT);  //可以ctrl+c或kill/kill all通知程序退出  
  if (logfile.Open(argv[3],"a+")==false)
  {
    printf("打开日志文件失败(%s)。\n",argv[3]); return -1;
  }
  while (true)  //可把while (true)一行和sleep(60)去除,用crontab调度
  {
    // 从站点参数文件中加载到vstcode容器中,argv[0]计算机从0开始
    if (LoadSTCode(argv[1])==false) { sleep(60); continue; }    
    logfile.Write("加载参数文件(%s)成功!\n",argv[1]);
    CrtSurfData();  // 生成全国气象站点分钟观测数据,存放在vsurfdata容器中
    // 把容器vsurfdata中的全国气象站点分钟观测数据写入文件
    if (CrtSurfFile(argv[2])==false) { sleep(60); continue; }
    sleep(60);  // 进入死循环60s执行一次,自身调度自己
  }
  return 0;
} 

//11111111111111111111.从站点参数文件中加载到vstcode容器中
bool LoadSTCode(const char *inifile)
{
  vstcode.clear();
  CCmdStr CmdStr;  // CmdStr类(_public.h中)切分并暂存字符串
  struct st_stcode stcode;  // st_stcode为数据结构,stcode为结构体变量
  CFile File;
  if (File.Open(inifile,"r") == false)
  {
    logfile.Write("File.Open(%s) 失败。\n",inifile); return false;
  }
  char strbuffer[101];  //101个字节可以存放50个汉字  strbuffer就是stcode.ini站点参数内容
  while (true)
  {
    memset(&stcode,0,sizeof(struct st_stcode));
    // memset(strbuffer,0,sizeof(strbuffer)); 因为Fgets里有初始化,所以这行省去    
    if (File.Fgets(strbuffer,100)==false) break; // 读取一行,在循环里就多行读取,break不能写成return false
    CmdStr.SplitToCmd(strbuffer,",",true); // true为删除空格,CmdStr里存了一行拆分后的片段,循环里就是多行
    CmdStr.GetValue(0, stcode.provname);  //stcode.provname就存了拆分的值,在循环里
    CmdStr.GetValue(1, stcode.obtid);     //GetValue做了重载,有第三个参数取长度
    CmdStr.GetValue(2, stcode.cityname);
    CmdStr.GetValue(3,&stcode.lat);  //double 传地址&
    CmdStr.GetValue(4,&stcode.lon);     
    CmdStr.GetValue(5,&stcode.height);
    vstcode.push_back(stcode);	
	// printf("strbuffer=%s",strbuffer);   //不需写成strbuffer=%s\n,因为文件本身有换行符
	// printf("provname=%s,obtid=%s,lat=%.2lf\n.....",stcode.provname,stcode.obtid,stcode.lat,......);
  }
  return true;
}

//1111111111111111112.创建全国气象站点分钟观测数据,存放在vsurfdata容器中,//Crt是create缩写
void CrtSurfData()  // 返回一定会成功的,所以不需要返回值void
{
  vsurfdata.clear();  // 清空容器
  srand(time(0));     // 播随机数种子  
  char strLocalTime[21];  
  LocalTime(strLocalTime,"yyyy-mm-dd hh24:mi"); // LocalTime3个参数:一:存放时间的字符串。二:取出当前时间用什么格式。三:时间偏移量秒。将memset(strLocalTime,0,sizeof(strLocalTime));放入LocalTime()中
  strcat(strLocalTime,":00"); //不计秒,里面800多行记录时间和文件名时间一样就把秒变成00
  struct st_surfdata stsurfdata;
  for (int ii=0;ii<vstcode.size();ii++)  //根据站点代码个数
  {
    memset(&stsurfdata,0,sizeof(struct st_surfdata)); 
    STRCPY(stsurfdata.obtid,10,vstcode[ii].obtid);  // 站点代码  //STRCPY(目的,长度,源)
    // LocalTime(stsurfdata.ddatetime);
    STRCPY(stsurfdata.ddatetime,20,strLocalTime);   // 数据时间采用当前时间
    stsurfdata.t=rand()%351;       // 气温:单位,0.1摄氏度  // 结构体值 //0-350间整数就行
    stsurfdata.p=rand()%265+10000; // 气压:0.1百帕  //0到264再加10000就是10000到10264
    stsurfdata.u=rand()%100+1;     // 相对湿度,1-100之间的值。
    stsurfdata.wd=rand()%360;      // 风向,0-360之间的值。
    stsurfdata.wf=rand()%150;      // 风速:单位0.1m/s
    stsurfdata.r=rand()%16;        // 降雨量:0.1mm
    stsurfdata.vis=rand()%5001+100000;  // 能见度:0.1米
    vsurfdata.push_back(stsurfdata);
  }
}

//1111111111111111113.把容器vsurfdata中的全国气象站点分钟观测数据写入文件
bool CrtSurfFile(const char *outpath)
{
  CFile File;
  char strLocalTime[21];
  LocalTime(strLocalTime,"yyyymmddhh24miss");
  char strFileName[301]; //目录名+文件名即下行outpath+/SURF_ZH_%s_%d.txt,初始化也在SNPRINTF中
  SNPRINTF(strFileName,300,"%s/SURF_ZH_%s_%d.txt",outpath,strLocalTime,getpid());  // outpath目录名   
  if (File.OpenForRename(strFileName,"w")==false)
  {
    logfile.Write("File.Open(%s) 失败!\n",strFileName); return false; // 不用printf显示到屏幕了
  }
  for (int ii=0;ii<vsurfdata.size();ii++) //装进容器里就是为了这行循环
  {
    // 站点代码,数据时间,气温,气压,相对湿度,风向,风速,降雨量,能见度  //存进容器的是整数,除以小数得小数显示到文件中
    File.Fprintf("%s,%s,%.1f,%.1f,%d,%d,%.1f,%.1f,%.1f\n",\
         vsurfdata[ii].obtid,vsurfdata[ii].ddatetime,vsurfdata[ii].t/10.0,vsurfdata[ii].p/10.0,\
         vsurfdata[ii].u,vsurfdata[ii].wd,vsurfdata[ii].wf/10.0,vsurfdata[ii].r/10.0,vsurfdata[ii].vis/10.0);
  }
  File.CloseAndRename();   // 关闭文件
  logfile.Write("生成数据文件(%s)成功,数据时间=%s,记录数=%d!\n\n",strFileName,vsurfdata[0].ddatetime,vsurfdata.size()); 
  // 数据时间=和文件名时间一样就是最后秒改为00(即文件里839行【vsurfdata.size()行】记录时间)
  vstcode.clear(); vsurfdata.clear(); //这里不清空容器,记录数=839,1678....(除非每次运行都重新make,不然要清空容器)
  return true;
}
void EXIT(int sig)
{
  logfile.Write("程序退出,sig=%d\n\n",sig);  // killall crtsurfdata ,.log日志文件中记录了:时间..程序退出,sig=15
  exit(0); //exit(0)程序退出自然会调用logfile的析构函数,所以这里不需要调用
}

在这里插入图片描述
一个.ini文件839行记录不同时间可生成多个.txt文件也有839行记录,一个.txt文件站点代码不同但时间一样。下面为改进版可选择生成.xml文件。

//crtsurfdata1.cpp生成的数据文件支持txt和xml两种格式
#include "_public.h"
#include "_shqx.h" // _shqx.h里包含st_stcode,st_surfdata两个结构体
vector<struct st_stcode> vstcode;   // 存放全国站点参数的容器
vector<struct st_surfdata> vsurfdata;   // 存放全国气象站点分钟观测数据的容器
// 从站点参数文件中加载到vstcode容器中
bool LoadSTCode(const char *inifile);
// 创建全国气象站点分钟观测数据,存放在vsurfdata容器中
void CrtSurfData();
// 把容器vsurfdata中的全国气象站点分钟观测数据写入文件
bool CrtSurfFile(const char *outpath,const char *datafmt);
CLogFile logfile;
void EXIT(int sig);

int main(int argc,char *argv[],char *envp[])
{
  if (argc!=5)
  {
    printf("\n本程序用于生成全国气象站点观测的分钟数据,与crtsurfdata程序不同,本程序生成的数据文件支持txt和xml两种格式。\n");
    printf("/htidc/shqx/bin/crtsurfdata1 站点参数 数据文件存放的目录 日志文件名 数据格式[txt|xml]\n");
    printf("例如:/htidc/shqx/bin/crtsurfdata1 /htidc/shqx/ini/stcode.ini /data/shqx/ftp/surfdata1 /log/shqx/crtsurfdata1.log txt\n");
    printf("      /htidc/shqx/bin/crtsurfdata1 /htidc/shqx/ini/stcode.ini /data/shqx/ftp/surfdata1 /log/shqx/crtsurfdata1.log xml\n");
    return -1;
  }
  // 关闭全部的信号和输入输出
  CloseIOAndSignal();
  // 处理程序退出的信号
  signal(SIGINT,EXIT); signal(SIGTERM,EXIT);
  if (logfile.Open(argv[3],"a+")==false)
  {
    printf("打开日志文件失败(%s)。\n",argv[3]); return -1;
  }
  while (true)
  {
    // 从站点参数文件中加载到vstcode容器中
    if (LoadSTCode(argv[1])==false) { sleep(60); continue; }
    logfile.Write("加载参数文件(%s)成功!\n",argv[1]);
    CrtSurfData();  // 创建全国气象站点分钟观测数据,存放在vsurfdata容器中
    // 把容器vsurfdata中的全国气象站点分钟观测数据写入文件
    if (CrtSurfFile(argv[2],argv[4])==false) { sleep(60); continue; }
    sleep(60);
  }
  return 0;
}

//1111111111111111111.从站点参数文件中加载到vstcode容器中
bool LoadSTCode(const char *inifile)
{
  vstcode.clear();
  CCmdStr CmdStr;
  struct st_stcode stcode;
  CFile File;
  if (File.Open(inifile,"r") == false)
  {
    logfile.Write("File.Open(%s) 失败。\n",inifile); return false;
  }
  char strbuffer[101];
  while (true)
  {
    memset(&stcode,0,sizeof(struct st_stcode));
    if (File.Fgets(strbuffer,100)==false) break;
    CmdStr.SplitToCmd(strbuffer,",",true);
    CmdStr.GetValue(0, stcode.provname);  //结构体值
    CmdStr.GetValue(1, stcode.obtid);
    CmdStr.GetValue(2, stcode.cityname);
    CmdStr.GetValue(3,&stcode.lat);
    CmdStr.GetValue(4,&stcode.lon);
    CmdStr.GetValue(5,&stcode.height);
    vstcode.push_back(stcode);
  }
  return true;
}

//1111111111111111112.创建全国气象站点分钟观测数据,存放在vsurfdata容器中
void CrtSurfData()
{
  vsurfdata.clear();  // 清空容器
  srand(time(0));  // 播随机数种子
  char strLocalTime[21];
  LocalTime(strLocalTime,"yyyy-mm-dd hh24:mi");
  strcat(strLocalTime,":00");
  struct st_surfdata stsurfdata;
  for (int ii=0;ii<vstcode.size();ii++)
  {
    memset(&stsurfdata,0,sizeof(struct st_surfdata));
    STRCPY(stsurfdata.obtid,10,vstcode[ii].obtid);  // 站点代码
    STRCPY(stsurfdata.ddatetime,20,strLocalTime);   // 数据时间采用当前时间
    stsurfdata.t=rand()%351;       // 气温:单位,0.1摄氏度
    stsurfdata.p=rand()%265+10000; // 气压:0.1百帕
    stsurfdata.u=rand()%100+1;     // 相对湿度,0-100之间的值。
    stsurfdata.wd=rand()%360;      // 风向,0-360之间的值。
    stsurfdata.wf=rand()%150;      // 风速:单位0.1m/s
    stsurfdata.r=rand()%16;        // 降雨量:0.1mm
    stsurfdata.vis=rand()%5001+100000;  // 能见度:0.1米
    vsurfdata.push_back(stsurfdata);
  }
}

//1111111111111111113.把容器vsurfdata中的全国气象站点分钟观测数据写入文件
bool CrtSurfFile(const char *outpath,const char *datafmt)
{
  CFile File;
  char strLocalTime[21];
  LocalTime(strLocalTime,"yyyymmddhh24miss");
  char strFileName[301];
  SNPRINTF(strFileName,300,"%s/SURF_ZH_%s_%d.%s",outpath,strLocalTime,getpid(),datafmt);   
  if (File.OpenForRename(strFileName,"w")==false)
  {
    logfile.Write("File.Open(%s) 失败!\n",strFileName); return false;
  }
  if (strcmp(datafmt,"xml")==0) File.Fprintf("<data>\n"); //开头加
  for (int ii=0;ii<vsurfdata.size();ii++)
  {
    // 站点代码,数据时间,气温,气压,相对湿度,风向,风速,降雨量,能见度
    if (strcmp(datafmt,"xml")==0)
    {
      File.Fprintf("<obtid>%s</obtid><ddatetime>%s</ddatetime><t>%.1f</t><p>%.1f</p><u>%d</u><wd>%d</wd><wf>%.1f</wf><r>%.1f</r><vis>%.1f</vis><endl/>\n",\
         vsurfdata[ii].obtid,vsurfdata[ii].ddatetime,vsurfdata[ii].t/10.0,vsurfdata[ii].p/10.0,\
         vsurfdata[ii].u,vsurfdata[ii].wd,vsurfdata[ii].wf/10.0,vsurfdata[ii].r/10.0,vsurfdata[ii].vis/10.0);
    }
    else
    {
      File.Fprintf("%s,%s,%.1f,%.1f,%d,%d,%.1f,%.1f,%.1f\n",\
         vsurfdata[ii].obtid,vsurfdata[ii].ddatetime,vsurfdata[ii].t/10.0,vsurfdata[ii].p/10.0,\
         vsurfdata[ii].u,vsurfdata[ii].wd,vsurfdata[ii].wf/10.0,vsurfdata[ii].r/10.0,vsurfdata[ii].vis/10.0);
    }
  }
  if (strcmp(datafmt,"xml")==0) File.Fprintf("</data>\n"); //结尾加
  File.CloseAndRename();   // 关闭文件
  logfile.Write("生成数据文件(%s)成功,数据时间=%s,记录数=%d!\n\n",strFileName,vsurfdata[0].ddatetime,vsurfdata.size());
  vstcode.clear(); vsurfdata.clear();
  return true;
}
void EXIT(int sig)
{
  logfile.Write("程序退出,sig=%d\n\n",sig);
  exit(0);
}

如下生成一个xml文件里也有800多行,最后也以< data >结尾。
在这里插入图片描述

2.ftp:ftp是tcp/ip协议族中一员,分客户端和服务端

2.1 安装:linux操作系统的用户也是ftp的用户,可以配置专用的ftp用户,专用的ftp用户只能用于ftp,不能登录操作系统

在这里插入图片描述
如下是ftp安装:安装ftp客户端:yum -y install ftp (remove)(只要ftp服务端安装并配置好防火墙等,任何主机安装了客户端都可以连上)。安装ftp服务端:yum -y install vsftpd (本地和远程服务器都可安装)。

如下是ftp服务端配置:1.防火墙开启 21 端口和5500-6000高端口
如果采用被动模式,防火墙开通21端口
(命令含义: --zone#作用域 --add-port=21/tcp#添加端口,格式为:端口/通讯协议 --permanent # 永久生效)
#firewall-cmd --zone=public --add-port=21/tcp --permanent
如果采用主动模式,防火墙还要开通20端口
#firewall-cmd --zone=public --add-port=20/tcp --permanent
#firewall-cmd --zone=public --add-port=5500-6000/tcp --permanent
(设置被动模式的高端口范围为5500-6000,passive命令为on,完成后必须init 6重启,netstat -na --ip,firewall-cmd --list-ports,防火墙配置不好可以直接关闭防火墙)

2.配置ftp高端口参数和关闭 selinux
#vi /etc/vsftpd/vsftpd.conf (必选装好vsftpd服务端,init6)

listen=YES  //将上面含有listen都注释掉
listen_ipv6=NO //关闭ipv6的监听,不然会ls,dir不出命令

pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES

pasv_min_port=5500
pasv_max_port=6000

pasv_enable=YES
pasv_address=47.100.167.156 //服务端公网ip

#vi /etc/selinux/config,修改成 selinux=disabled,执行 setenforce 0 使修改马上生效。
在这里插入图片描述
3.登录阿里云控制台实例安全组(如上配置不成功,手动配置端口)。
在这里插入图片描述
点击安全组列表中配置规则。
在这里插入图片描述
4.vsftpd服务端相关操作
systemctl start vsftpd # 启动
systemctl stop vsftpd # 停止
systemctl status vsftpd # 查看
systemctl enable vsftpd # 开机自动启动vsftpd服务(类似windows管理工具中服务)
systemctl disable vsftpd # 禁用vsftpd服务

5.防火墙服务相关操作
以下是centos7的命令:
centos7中的防火墙名改成了firewall
systemctl restart firewalld.service # 重启防火墙
systemctl stop firewalld.service # 关闭防火墙
systemctl start firewalld.service # 启动防火墙
systemctl status firewalld.service # 查看防火墙服务状态
systemctl enable firewalld.service # 开机禁用防火墙
以下是centos6的命令:
chkconfig iptables off # 开机禁用防火墙
service vsftpd restart # 重启ftp服务端
service iptables stop #关闭防火墙

2.2 ftp命令:get,put

登录ftp服务器:linux命令行输入:ftp ip地址,然后输入用户名和密码(adduser ,passwd ),必须先开启ftp服务

windows的命令提示符下有ftp客户端程序,但是不好用。 采用资源管理器,输入:ftp://服务器ip,如下图:
在这里插入图片描述
在空白的位置点鼠标右键,选择登录菜单, 输入用户名和密码登录ftp服务器界面,直接将文件拖到windows界面。
在这里插入图片描述

查看/下载/上传文件:ftp的传输模式分ASCII码和二进制两种,二进制可传输任何文件,而ASCII码方式只能传输.txt、.html,实际开发中,不管什么文件都用二进制传输文件省事

dir:显示服务器目录和文件列表
ls:显示服务器目录和文件列表
cd:进入服务器指定的目录
lcd:进入本地客户端指定的目录。lcd空可查看本地位置
(dir命令可以使用通配符“*”和“?”,比如,显示当前目录中所有扩展名为jpg的文件,可使用命令 dir *.jpg)

type:查看当前的传输方式
ascii:设定传输方式为ASCII码方式
binary:设定传输方式为二进制方式
get/recv:下载单个文件get filename newname(filename为下载的ftp服务器上的文件名,newname为保存在本都计算机上时使用的名字,get/recv只能取文件(文件夹需要打包压缩),加-r可以操作文件夹
mget:下载多个文件mget filename filename ....(mget命令支持通配符“*”和“?”,比如:mget *.jpg 表示下载ftp服务器当前目录下的所有扩展名为jpg的文件。)
prompt:关闭/打开互交提示。关闭后,mget不用输入y

put/send:上传单个文件put filename newname,filename为上传的本地文件名,newname为上传至ftp服务器上时使用的名字,如果不指定newname,文件将以原名上传。
mput:上传多个文件mput filename filename ....,mput命令支持通配符“*”和“?”
bye:结束与服务器的ftp会话并退出ftp环境
pwd:查看ftp服务器上的当前工作目录
rename filename newfilename:重命名ftp服务器上的文件
delete filename:删除ftp服务器上一个文件。
mdelete [remote-files] :删除多个文件。
mkdir pathname:在服务器上创建目录。
rmdir pathname:删除服务器上的目录。
passive:主动模式与被动模式切换。
nlist:列出服务器目录中的文件名,如:nlist /home/w /tmp/tmp.list,表示把服务器上/home/w目录下的文件列出来,结果输出到本地的/tmp/tmp.list文件中,输出文件名是全路径。
help [cmd]:显示ftp命令的帮助信息,cmd是命令名,如果不带参数,则显示所有ftp命令。

2.3 ftp应用:OpenForRename,Fgets

数据完整性:在一文件夹里 ls | wc 统计数据行数

如下exit退出csh,不然export等命令行命令在cshell中执行不了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以下用C语言实现ftp客户端,File.Open>写文件>File.close是需要时间的,写文件过程中ftp将这文件取走的话,取走的文件不完整,如果是银行数据不可行。如下有两个数据不完整不安全环节。
在这里插入图片描述
第一环节供ftp用:创建文件SNPRINTF命名为.txt.tmp,读取Open文件.txt.tmp,数据写完后才会close再rename为.txt,避免文件还没Close被取走。第二环节供处理数据程序用:避免ftp没有get完被处理数据程序取走。
在这里插入图片描述
下面在本地rename,这样两步就能避免中间状态文件被读取。
在这里插入图片描述
下面修改crtsurfdata.cpp。
在这里插入图片描述
sleep(20);// 停20秒方便观看。
在这里插入图片描述

C语言实现ftp下载文件:.a就是静态库相当.c/.cpp一个别名,编译时不让人看见,makefile中libftp.a就是ftplib.c。

如下demo18用到_ftp.h(连着_ftp.cpp一起编译),_ftp.h又用到ftplib.h(连着ftplib.c一起编译,.h必用到其实现的.c/.cpp)ftplib.h和ftplib.c源代码链接:https://pan.baidu.com/s/1P_GTtiOpMnO3KqU6_VVnzQ,提取码:u77a。

// 记住复制时第一行完整CC,一个tab缩进
CC=g++
FLAG=-g
#FLAG=-02

all:crtsurfdata libftp.a demo18 ftpgetfiles

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

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

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

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

clean:
        rm -rf crtsurfdata demo18 ftpgetfiles libftp
// 本程序演示Cftp客户端类,采用ftp协议从服务器上获取文件,demo18.cpp
#include "_ftp.h"
int main(int argc,char *argv[])
{
  Cftp ftp; 
  // 登录远程FTP服务器
  if (ftp.login("193.112.16.23:21","用户名","密码",FTPLIB_PASSIVE) == false)
  {
    printf("ftp.login() failed.\n"); return -1;
  }  
  ftp.mtime("/home/y/surfdata/SURF_ZH_20200209122402_2815.txt");
  ftp.size("/home/y/surfdata/SURF_ZH_20200209122402_2815.txt");
  printf("=%s=\n",ftp.response());  
  // 改变本地目录
  chdir("/tmp");
  // 进入ftp服务器上文件存放的目录
  if (ftp.chdir("/home/y/surfdata") == false)
  {
    printf("ftp.chdir() failed.\n"); return -1;
  }
  // 获取对方目录文件的列表,存放在"/tmp/ftp.list"文件中
  if (ftp.nlist("*.txt","/tmp/ftp.list")== false)
  {
    printf("ftp.nlist() failed.\n"); return -1;
  }
  CFile File;
  File.OpenForRead("/tmp/ftp.list","r");    
  // 逐行读取文件的内容,并把文件get到本地
  char strFileName[101];
  while (true)
  {
    // 从文件中读取一行
    memset(strFileName,0,sizeof(strFileName));
    if (File.Fgets(strFileName,100) == false) break;    
    strFileName[strlen(strFileName)-1]=0; //去除最后回车符    
    printf("get %s ...",strFileName);
    // 从远程取文件
    if (ftp.get(strFileName,strFileName)==false)
    {
      printf("ftp.get(%s) failed.\n",strFileName); break;
    }
    printf("ok.\n");
  }
  File.CloseAndRemove();
  ftp.logout();
  return 0;
}

在这里插入图片描述

// _ftp.h
#ifndef __FTP_H
#define __FTP_H
#include "_public.h"
#include "ftplib.h"
class Cftp
{
public:
  // ftp连接句柄
  netbuf *m_ftpconn;
  // 文件的大小
  unsigned int m_size;
  // 文件的时间modifytime
  char m_mtime[21];
  Cftp();
 ~Cftp();
  // 存放login()方法登录失败的原因
  bool m_connectfailed;
  bool m_loginfailed;
  bool m_optionfailed;  
  void initdata();
  
  // 登录ftp服务器
  // in_host 服务器地址和端口,中间用":"分隔,如"192.168.1.1:21"
  // in_username ftp用户名
  // in_password ftp的密码
  // in_mode 传输模式,FTPLIB_PASSIVE是被动模式,FTPLIB_PORT是主动模式
  bool login(const char *in_host,const char *in_username,const char *in_password,const int in_mode=FTPLIB_PASSIVE);  
  // 注销
  bool logout();
  // 获取ftp服务器上文件的时间
  bool mtime(const char *in_remotefilename);
  // 获取ftp服务器上文件的大小
  bool size(const char *in_remotefilename);
  // 向服务端发送site命令
  bool site(const char *in_command);
  // 改变ftp远程目录
  bool chdir(const char *in_remotedir);
  // 在ftp服务器上创建目录
  bool mkdir(const char *in_remotedir);
  // 删除ftp服务器上的目录
  bool rmdir(const char *in_remotedir);
  // 发送list命令列出ftp服务器目录中的文件,结果保存到本地文件中
  // 如果是列出当前目录,in_remotedir用"","*","."都行。
  bool nlist(const char *in_remotedir,const char *out_listfilename);
  // 发送dir命令列出ftp服务器目录中的文件,结果保存到本地文件中
  bool dir(const char *in_remotedir,const char *out_listfilename);
  // 从ftp服务器上获取文件
  // in_remotefilename 待获取的远程文件名
  // in_localfilename  本地文件名,可以与in_remotefilename不同
  // bCheckMTime 文件传输完成后,是否核对文件传输前后的时间,保证文件的完整性
  // 注意,文件在传输的过程中,采用临时文件命名的方法,即在in_localfilename后加".tmp",在传输
  // 完成后才正式改为in_localfilename
  bool get(const char *in_remotefilename,const char *in_localfilename,const bool bCheckMTime=true);
  // 向ftp服务器发送文件
  // in_localfilename 本地待发送的文件名
  // in_remotefilename 远程文件名
  // bCheckSize 文件传输完成后,是否核对本地和远程文件的大小,保证文件的完整性
  // 注意,文件在传输的过程中,采用临时文件命名的方法,即在in_remotefilename后加".tmp",在传输
  // 完成后才正式改为in_remotefilename
  bool put(const char *in_localfilename,const char *in_remotefilename,const bool bCheckSize=true);
  // 删除ftp服务器上的文件
  bool ftpdelete(const char *in_remotefilename);
  // 把ftp服务器上的文件改名
  bool ftprename(const char *in_srcremotefilename,const char *in_dstremotefilename);
  // 获取服务器返回信息的最后一条 return a pointer to the last response received
  char *response();
};
#endif

如下bool Cftp::mtime()中AddTime()在_public.cpp实现,注意"yyyymmddhh24miss"格式

// _ftp.cpp
#include "_ftp.h"
Cftp::Cftp()
{
  m_ftpconn=0;
  initdata();
  FtpInit();
  m_connectfailed=false;
  m_loginfailed=false;
  m_optionfailed=false;
}

Cftp::~Cftp()
{
  logout();
}

void Cftp::initdata()
{
  m_size=0;

  memset(m_mtime,0,sizeof(m_mtime));
}

bool Cftp::login(const char *in_host,const char *in_username,const char *in_password,const int in_mode)
{
  if (m_ftpconn != 0) { FtpQuit(m_ftpconn); m_ftpconn=0; }

  m_connectfailed=m_loginfailed=m_optionfailed=false;

  if (FtpConnect(in_host,&m_ftpconn) == false)  { m_connectfailed=true; return false; }

  if (FtpLogin(in_username,in_password,m_ftpconn) == false)  { m_loginfailed=true; return false; }

  if (FtpOptions(FTPLIB_CONNMODE,(long)in_mode,m_ftpconn) == false) { m_optionfailed=true; return false; }

  return true;
}

bool Cftp::logout()
{
  if (m_ftpconn == 0) return false;

  FtpQuit(m_ftpconn);

  m_ftpconn=0;

  return true;
}

bool Cftp::get(const char *in_remotefilename,const char *in_localfilename,const bool bCheckMTime)
{
  if (m_ftpconn == 0) return false;

  // 创建本地文件目录
  MKDIR(in_localfilename);

  char strlocalfilenametmp[301];
  memset(strlocalfilenametmp,0,sizeof(strlocalfilenametmp));
  snprintf(strlocalfilenametmp,300,"%s.tmp",in_localfilename);

  // 获取远程服务器的文件的时间
  if (mtime(in_remotefilename) == false) return false;

  // 取文件
  if (FtpGet(strlocalfilenametmp,in_remotefilename,FTPLIB_IMAGE,m_ftpconn) == false) return false;
  
  // 判断文件获取前和获取后的时间,如果时间不同,表示文件已改变,返回失败
  if (bCheckMTime==false)
  {
    char strmtime[21];
    strcpy(strmtime,m_mtime);

    if (mtime(in_remotefilename) == false) return false;

    if (strcmp(m_mtime,strmtime) != 0) return false;
  }

  // 重置文件时间
  UTime(strlocalfilenametmp,m_mtime);

  // 改为正式的文件
  if (rename(strlocalfilenametmp,in_localfilename) != 0) return false; 

  // 获取文件的大小
  m_size=FileSize(in_localfilename);

  return true;
}

bool Cftp::mtime(const char *in_remotefilename)
{
  if (m_ftpconn == 0) return false;
  
  memset(m_mtime,0,sizeof(m_mtime));
  
  char strmtime[21];
  memset(strmtime,0,sizeof(strmtime));

  if (FtpModDate(in_remotefilename,strmtime,14,m_ftpconn) == false) return false;

  AddTime(strmtime,m_mtime,0+8*60*60,"yyyymmddhh24miss");

  return true;
}

bool Cftp::size(const char *in_remotefilename)
{
  if (m_ftpconn == 0) return false;

  m_size=0;
  
  if (FtpSize(in_remotefilename,&m_size,FTPLIB_IMAGE,m_ftpconn) == false) return false;

  return true;
}

bool Cftp::site(const char *in_command)
{
  if (m_ftpconn == 0) return false;
  
  if (FtpSite(in_command,m_ftpconn) == false) return false;

  return true;
}

bool Cftp::chdir(const char *in_remotedir)
{
  if (m_ftpconn == 0) return false;
  
  if (FtpChdir(in_remotedir,m_ftpconn) == false) return false;

  return true;
}

bool Cftp::mkdir(const char *in_remotedir)
{
  if (m_ftpconn == 0) return false;
  
  if (FtpMkdir(in_remotedir,m_ftpconn) == false) return false;

  return true;
}

bool Cftp::rmdir(const char *in_remotedir)
{
  if (m_ftpconn == 0) return false;
  
  if (FtpRmdir(in_remotedir,m_ftpconn) == false) return false;

  return true;
}

bool Cftp::dir(const char *in_remotedir,const char *out_listfilename)
{
  if (m_ftpconn == 0) return false;
  
  if (FtpDir(out_listfilename,in_remotedir,m_ftpconn) == false) return false;

  return true;
}

bool Cftp::nlist(const char *in_remotedir,const char *out_listfilename)
{
  if (m_ftpconn == 0) return false;

  // 创建本地文件目录
  MKDIR(out_listfilename);
  
  if (FtpNlst(out_listfilename,in_remotedir,m_ftpconn) == false) return false;

  return true;
}

bool Cftp::put(const char *in_localfilename,const char *in_remotefilename,const bool bCheckSize)
{
  if (m_ftpconn == 0) return false;

  char strremotefilenametmp[301];
  memset(strremotefilenametmp,0,sizeof(strremotefilenametmp));
  snprintf(strremotefilenametmp,300,"%s.tmp",in_remotefilename);

  if (FtpPut(in_localfilename,strremotefilenametmp,FTPLIB_IMAGE,m_ftpconn) == false) return false;

  if (FtpRename(strremotefilenametmp,in_remotefilename,m_ftpconn) == false) return false;

  // 判断已上传的文件的大小与本地文件是否相同,确保上传成功。
  if (bCheckSize==true)
  {
    if (size(in_remotefilename) == false) return false;

    if (m_size != FileSize(in_localfilename)) return false; 
  }

  return true;
}

bool Cftp::ftpdelete(const char *in_remotefilename)
{
  if (m_ftpconn == 0) return false;

  if (FtpDelete(in_remotefilename,m_ftpconn) == false) return false;
  
  return true;
}

bool Cftp::ftprename(const char *in_srcremotefilename,const char *in_dstremotefilename)
{
  if (m_ftpconn == 0) return false;

  if (FtpRename(in_srcremotefilename,in_dstremotefilename,m_ftpconn) == false) return false;
  
  return true;
}

char *Cftp::response()
{
  if (m_ftpconn == 0) return 0;

  return FtpLastResponse(m_ftpconn);
}

结构化数据:有记录有条数,操作数据库,传文件,调http接口。非结构化数据:图片,视频,word文档,ftp(数据中心中结构化数据用操作数据库推上云,非结构化数据用ftp推上云)。
在这里插入图片描述
在这里插入图片描述
上面strbuffer[…-1]只删除linux下\n换行符效果如下,window下\r不能删除,也可能会有两个\r。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下获取到了服务器上文件时间,filename是相对路径,后面拼成绝对路径。
在这里插入图片描述

// 从ftp服务器上采集文件,ftpgetfiles.cpp,TCP客户端
#include"_public.h"
#include"_ftp.h"
struct st_arg
{
  char host[51];
  int  mode;
  char username[31];
  char password[31];
  char localpath[301];
  char remotepath[301];
  char matchname[301];
  int  ptype;	
  char remotepathbak[301];
  char listfilename[301];
  char okfilename[301];
  int  timetvl;
} starg;
/*
struct st_fileinfo
{ //在_public.h中定义了
  char filename[301];
  char mtime[21];
};
*/
vector<struct st_fileinfo> vokfilename,vokfilename1;
vector<struct st_fileinfo> vlistfile,vlistfile1;	
Cftp ftp;		
CLogFile  logfile;	//全局变量,日志操作类对象
//把nlist获取的文件名加载到vlistfile容器中
bool LoadListFile();
//把okfilename文件的内容加载到voklistname容器中
bool LoadOKFileName();
//比较vlistfile容器与vokfilename中的文件,得到新的两个容器
bool CompVector();
//把vokfilename1容器里的内容先写入okfilename文件中,覆盖之前的旧okfilename文件
bool WriteToOKFileName();
//ptype=1,把采集成功的文件追加到okfilename文件中
bool AppendToOKFileName(struct st_fileinfo *stfileinfo);
//退出信号的处理函数
void EXIT(int sig);
//本程序的业务流程的主函数
bool _ftpgetfile();	
//显示文件的帮助
void _help(char *argv[]);
//把xml参数读取到starg结构体中
bool _xmltoarg(char *strxmlbuffer);

int main(int argc,char *argv[])  //这样写,()里不为空则将命令行作为参数传入
{
  if(argc != 3)
  {
    _help(argv); //argv是数组名也就是地址
    return -1;
  }
  //关闭全部的信号和输入输出
  CloseIOAndSignal();
  //处理程序退出的信号
  signal(SIGINT,EXIT);		//中断信号
  signal(SIGTERM,EXIT);		//kill信号  
  if(logfile.Open(argv[1],"a+") == false)
  {
    logfile.Write("打开日志文件(%s)失败。\n",argv[1]); // logout会自动调用_ftp.h里析构函数,所以不用写
    return -1;
  }
  if(_xmltoarg(argv[2]) == false)
    return -1;
  while(true)
  {
    if((ftp.login(starg.host,starg.username,starg.password,starg.mode)) == false)
    { 
      logfile.Write("ftp.login(%s,%s,%s) failed.\n",starg.host,starg.username,starg.password);
      //return -1;
	  sleep(starg.timetvl);
	  continue;
    }    
    //logfile.Write("ftp.login ok.\n"); 
    //本程序的业务流程的主函数
    _ftpgetfile();
	ftp.logout();
	sleep(starg.timetvl);
  }
  return 0;
}

//111111111111111111111111111111111111111111111111111111111111.本程序的业务流程的主函数
bool _ftpgetfile()
{
  //先chdir进入目录,这样listfilename输出就不是全路径了,节省文件大小,减小网络开销
  if(ftp.chdir(starg.remotepath) == false) 
  {
    logfile.Write("ftp.chdir(%s) failed.\n",starg.remotepath);
    return false;
  }
  //logfile.Write("chdir ok.\n");
  //nlist列出服务器目录文件并自动创建listfilename前面目录 。ftp.mtime比ftp.nlist更耗时
  //每次取时和listfilename做对比实现增量采集,已chdir进入目录所以用圆点(空和星号都可以)
  if(ftp.nlist(".",starg.listfilename) == false)   
  {
    logfile.Write("ftp.nlist(%s) failed.\n",starg.remotepath);
    return false;
  }
  //logfile.Write("nlist ok.\n");
  //把nlist获取的文件加载到vlistfile容器中,一般LoadListFile不会返回失败,但是里面有ftp.mtime联网可能会返回失败
  if(LoadListFile() == false)
  {
    logfile.Write("LoadListFile failed.\n");
    return -1;
  }  
 
  //chdir(starg.localpath); //切换本地工作目录,如果这目录不存在就切换不成功,所以不用这方法,用绝对路径
  if(starg.ptype == 1)
  {
    //okfilename是xml文件格式<filename>SURF_ZH_20190913131401_22226.txt</filename><mtime>20191026212900</mtime>
    //加载okfilename文件里的内容到容器vokfilename里
    LoadOKFileName();
    //把vlistfile容器中的文件与vokfilename中的文件对比,得到新的两个容器
//1.在vlistfile中存在,并已经采集成功的文件vokfilename1
//2.在vlistfile中存在,新文件(vlistfile有,vokfilename没有)或要重新采集(vlistfile与vokfilename文件时间不同)的文件vlistfile1
    CompVector();    
    //把vokfilename1容器里的内容先写入okfilename文件中,覆盖之前的旧okfilename文件
    WriteToOKFileName();    
    //把vlistfile1容器中的内容复制到vlistfile容器中让下面代码都可用
    //vlistfile.clear();
    vlistfile.swap(vlistfile1);
  }

  for(int i=0;i<vlistfile.size();i++)
  {
    char strremotefilename[301],strlocalfilename[301]; //不切换本地工作目录了,定义两个变量拼成绝对路径  
    SNPRINTF(strlocalfilename,300,"%s/%s",starg.localpath,vlistfile[i].filename); 
    SNPRINTF(strremotefilename,300,"%s/%s",starg.remotepath,vlistfile[i].filename);
    //vlistfile为string时,vlistfile[i].c_str()。为struct时push_back进去,vlistfile[i].filename
    logfile.Write("get %s ...",strremotefilename);
    //获取文件
    if(ftp.get(strremotefilename,strlocalfilename,true) == false )
    {
      logfile.WriteEx("failed.\n"); //WriteEx不写时间
      break;
    }
    logfile.WriteEx("ok.\n");
    //删除文件
    if (starg.ptype==2) ftp.ftpdelete(strremotefilename);    
    //转存到备份目录
    if(starg.ptype == 3)
    {
      char strremotefilenamebak[301];  //remotepathbak不要自己创建
      SNPRINTF(strremotefilenamebak,300,"%s/%s",starg.remotepathbak,vlistfile[i].filename); //拼成
      ftp.ftprename(strremotefilename,strremotefilenamebak);
    }
    //ptype=1,把采集成功的文件追加到okfilename文件中
    if(starg.ptype == 1)
    {
      AppendToOKFileName(&vlistfile[i]);
    }      
  }
  return true;
}
void EXIT(int sig)
{
  logfile.Write("程序退出,sig=%d\n",sig);
  exit(0);
}

//1111111111111111111111111111111111111111111111111111111.1 加载对方服务器文件列表
bool LoadListFile() // 和crtsurfdata.cpp中LoadSTCode()差不多
{
  vlistfile.clear();
  CFile file;
  if(file.Open(starg.listfilename,"r") == false)
  {
    logfile.Write("file.Open(%s) failed.\n",starg.listfilename);
    return false;
  }  
  struct st_fileinfo stfileinfo;
  while(true)
  {
    memset(&stfileinfo,0,sizeof(stfileinfo));
    if(file.Fgets(stfileinfo.filename,300,true) == false) 
      break;
    //或许放在对比完下载文件的时候更合适?
    if(MatchFileName(stfileinfo.filename,starg.matchname) == false)
      continue; //文件名不符合要求的话就不要
    if(starg.ptype == 1 )
    {
      //获取服务器文件时间  //这边可能会网络交互时返回失败,所以记日志 //只有ptype == 1才需要获取文件时间
      if(ftp.mtime(stfileinfo.filename) == false)
      {
	    logfile.Write("ftp.mtime(%s) failed.\n",stfileinfo.filename);
        return false;
      }
      strcpy(stfileinfo.mtime,ftp.m_mtime);  //m_mtime在_ftp.h中AddTime,mtime成员函数中
    }      
    vlistfile.push_back(stfileinfo);
    //logfile.Write("vlistfile filename=%s,mtime=%s\n",stfileinfo.filename,stfileinfo.mtime);
  }
  return true;
}

//111111111111111111111111111111111111111111111111111.2 加载采集成功文件列表
bool LoadOKFileName()   //打开,读,解析到结构体,push进容器
{
  vokfilename.clear();
  CFile file;
  //如果程序是第一次采集,okfilename是不存在的,并不是错误,也返回true
  if(file.Open(starg.okfilename,"r") == false)
    return true;
  struct st_fileinfo stfileinfo;
  char strbuffer[301];
  while(true)
  {
    memset(&stfileinfo,0,sizeof(stfileinfo));
    if(file.Fgets(strbuffer,300,true) == false) 
      break;
    GetXMLBuffer(strbuffer,"filename",stfileinfo.filename,300);
    GetXMLBuffer(strbuffer,"mtime",stfileinfo.mtime,20);
    vokfilename.push_back(stfileinfo);
    //logfile.Write("vokfilename filename=%s,mtime=%s\n",stfileinfo.filename,stfileinfo.mtime);
  }
  return true;
}

//11111111111111111111111111111111111111.3 把vlistfile容器中的文件与vokfilename中的文件对比,得到新的两个容器
bool CompVector()
{
  vokfilename1.clear();
  vlistfile1.clear();
  for(int i=0;i<vlistfile.size();i++)  //这个循环得到vlistfile1
  {
    int j=0; //在外面定义下面可以用j
    for(j=0;j<vokfilename.size();j++)  //这个循环得到vokfilename1
    {
      if( (strcmp(vlistfile[i].filename,vokfilename[j].filename)) == 0 &&
          (strcmp(vlistfile[i].mtime,vokfilename[j].mtime)) == 0 )  //文件名和时间等的话不需要再取
      {
        vokfilename1.push_back(vlistfile[i]); break; //不满足上面两个条件,break跳出
      }
    }
    //如下跳出for(j=0;j<vokfilename.size();j++)循环得到vlistfile1
    if(j == vokfilename.size()) //因为j<vokfilename.size(),所以这行意思是肯定没找到两个相等的
      vlistfile1.push_back(vlistfile[i]);   //if省略了{}
  }
/*
  //用于调试
  for(int i=0;i<vlistfile1.size();i++)
  {
    logfile.Write("vlistfile1 filename=%s,mtime=%s\n",vlistfile1[i].filename,vlistfile1[i].mtime);
  }
  for(int i=0;i<vokfilename1.size();i++)
  {
    logfile.Write("vokfilename1 filename=%s,mtime=%s\n",vokfilename1[i].filename,vokfilename1[i].mtime);
  }
*/
  return true;
}

//11111111111111111111111111111.4 把vokfilename1容器里的内容先写入okfilename文件中,覆盖之前的旧okfilename文件
bool WriteToOKFileName()
{
  CFile file;
  if(file.Open(starg.okfilename,"w") == false)
  {
    logfile.Write("file.Open(%s) failed.\n",starg.okfilename);
    return false;
  }  
  for(int i=0;i<vokfilename1.size();i++)  //通用固定写法
  {
    file.Fprintf("<filename>%s</filename><mtime>%s</mtime>\n",vokfilename1[i].filename,vokfilename1[i].mtime);
  }
  return true;
}

//1111111111111111111111111111111111111111111111.5 ptype=1,把采集成功的文件追加到okfilename文件中
bool AppendToOKFileName(struct st_fileinfo *stfileinfo) //okfilename文件名是自己写进参数,一开始文件内容空
{
  CFile file;
  if(file.Open(starg.okfilename,"a") == false)
  {
    logfile.Write("file.Open(%s) failed.\n",starg.okfilename);
    return false;
  }  
  // 如下写入一行,传入 *stfileinfo指针
  file.Fprintf("<filename>%s</filename><mtime>%s</mtime>\n",stfileinfo->filename,stfileinfo->mtime);
  return true;
}

//111111111111111111111111111111111111111111111112.把xml参数读取到starg结构体中
bool _xmltoarg(char *strxmlbuffer)
{
  memset(&starg,0,sizeof(struct st_arg));
  GetXMLBuffer(strxmlbuffer,"host",starg.host);
  if(strlen(starg.host) == 0) 
  { logfile.Write("host is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"mode",&starg.mode);
  if( (starg.mode != 1) && (starg.mode != 2) ) 
    starg.mode = 1;
  GetXMLBuffer(strxmlbuffer,"username",starg.username);
  if(strlen(starg.username) == 0) 
  { logfile.Write("username is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"password",starg.password);
  if(strlen(starg.password) == 0) 
  { logfile.Write("password is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"localpath",starg.localpath);
  if(strlen(starg.localpath) == 0) 
  { logfile.Write("localpath is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"remotepath",starg.remotepath);
  if(strlen(starg.remotepath) == 0) 
  { logfile.Write("remotepath is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"matchname",starg.matchname);
  if(strlen(starg.matchname) == 0) 
  { logfile.Write("matchname is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"ptype",&starg.ptype);
  if( (starg.ptype != 1) && (starg.ptype != 2) && (starg.ptype != 3)) 
  { logfile.Write("ptype is error.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"remotepathbak",starg.remotepathbak);
  if( (starg.ptype == 3) && (strlen(starg.remotepathbak) == 0)) 
  { logfile.Write("remotepathbak is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"listfilename",starg.listfilename);
  if(strlen(starg.listfilename) == 0) 
  { logfile.Write("listfilename is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"okfilename",starg.okfilename);
  if( (starg.ptype == 1) && (strlen(starg.okfilename) == 0)) 
  { logfile.Write("okfilename is null.\n"); return false;}
  GetXMLBuffer(strxmlbuffer,"timetvl",&starg.timetvl);
  if( (starg.timetvl) == 0) 
  { logfile.Write("timetvl is null.\n"); return false;}
  return true;
}

//111111111111111111111111111111111111111111111113.显示文件的帮助
void _help(char *argv[])
{
    printf("\n公共模块,从ftp服务器上采集文件。\n");
    printf("/root/qxidc/bin/ftpgetfile logfilename xmlbuffer \n\n");
    printf("例如:/root/qxidc/bin/ftpgetfile /root/qxidc/log/ftpgetfile.log \"<host>47.100.16.15:21</host><mode>1</mode><username>y</username><password>5199</password><localpath>/root/qxidc/data/surfdata</localpath><remotepath>/home/yu/surfdata</remotepath><matchname>SURF_*.txt,*.DAT</matchname><ptype>1</ptype><remotepathbak></remotepathbak><listfilename>/root/qxidc/ftplist/ftpgetfile_surfdata.list</listfilename><okfilename>/root/qxidc/ftplist/ftpgetfile_surfdata.xml</okfilename><timetvl>30</timetvl> \"\n\n");
    printf("logfilename  程序运行的日志文件名 \n");
    printf("xmlbuffer  文件传输的参数,如下: \n");
    printf("<host>118.31.74.14:21</host>  远程服务器的IP和端口 \n");
    printf("<mode>1</mode>  传输模式,1-pasv(被动),2-port(主动),缺省为1 \n");
    printf("<username>gu</username>  远程服务器的ftp用户名 \n");
    printf("<password>98</password>  远程服务器的ftp密码 \n");
    printf("<localpath>/home/gu/tmp/ftpget</localpath>  本地文件存放的目录 \n");
    printf("<remotepath>/home/y/</remotepath>  远程服务器文件存放的目录 \n");
    printf("<matchname>*.GIF</matchname>  待采集文件匹配的文件名,大写匹配,"\
    	    "不匹配的文件不会被采集,尽量精确,不允许采用*匹配全部文件\n");
    printf("<ptype>2</ptype>  采集之后,服务器处理方式:1-什么都不做(增量采集),2-删除,3-备份 \n");
    printf("<remotepathbak>/home/y/bak</remotepathbak>  远程服务器文件备份的目录,只有当ptype=3时才有效 \n");
    printf("<listfilename>/home/gu/qxidc/list/ftpgetfile_surfdata.list</listfilename> 采集器列出服务器文件名的清单 \n");
    printf("<okfilename>/home/gu/qxidc/list/ftpgetfile_surfdata.xml</okfilename> 已采集成功文件名清单 \n");
    printf("<timetvl>30</timetvl> 采集时间间隔 单位:s 一般大于 10 \n\n");
    //不能多个程序共用listfilename和okfilename
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ROS2移动机器人导航仿真

环境&#xff1a;Ubuntu 18.04 ros2 eloquent wget http://fishros.com/install -O fishros && . fishros1.安装turtlebot3相关功能包 sudo apt install ros-eloquent-turtlebot3* ref&#xff1a; https://docs.ros.org/ ROS2导航SLAM建图探索_鱼香ROS的博客-CSD…

蛋白组学 代谢组

https://www.cnblogs.com/yanzhi123/p/11712926.htmlhttps://www.cnblogs.com/yanzhi123/p/11712926.html【3】蛋白质组学鉴定软件之Mascot - 简书 (jianshu.com) 【6】蛋白质组学鉴定定量软件之MaxQuant - 简书 (jianshu.com) 基于Maxquant软件处理的LabelFree蛋白质组学 首…

图灵第4期MySQL调优专题学习笔记

目录 一、首先复习打印的课件 二、Explain中的列 三、解读extra 四、索引最佳实践 五、MySQL的内部组结构 2. bin-log归档&#xff1a; 六、常见SQL深入优化 1. order by 与 group by 优化 2. 索引设计原则 3. 分页查询优化&#xff08;根据非主键字段排序的分页查询…

Verilog基础之十三、ROM实现

目录 一、前言 二、非IP核设计 2.1 工程设计文件读取初始化 2.2 测试代码 2.3 仿真结果 三、IP核创建ROM 3.1 IP核生成ROM 3.2 设计代码 3.3 测试代码 3.4 仿真结果 四、modelsim设置 4.1 模拟信号显示 4.2 信号范围显示设置 五、数据文件 一、前言 对于工程中的…

IMX6ULL系统移植篇-uboot启动Log信息

一. 进入uboot 命令模式 只有启动 uboot&#xff0c;进入 uboot的命令行模式时&#xff0c;才能使用 uboot 的命令。 当开发板启动时&#xff0c;快速按下回车键即可进入 uboot命令行模式。这时&#xff0c;进入 uboot 的命令行模式以后输入“help” 或者 “&#xff1f;” &a…

基因遗传进化算法-找最优路径

import random import matplotlib.pyplot as pltplt.rcParams["font.sans-serif"]["SimHei"] #设置字体 plt.rcParams["axes.unicode_minus"]False #该语句解决图像中的“-”负号的乱码问题# 创建初始种群 def create_initial_population():popu…

1024天,CSDN上的时间之旅

1024天&#xff0c;CSDN上的时间之旅 感想收获未来规划职业规划创作规划 感想 今天是在CSDN这个博客上成为博主已经迈入了1024天。这个数字对于计算机领域来说&#xff0c;具有特殊的含义和重要性。 在计算机科学中&#xff0c;1024是2的十次方&#xff0c;也就是2^10。这意味…

rt-thread------串口V1(三)接收

系列文章目录 rt-thread 之 fal移植 rt-thread 之 生成工程模板 STM32------串口理论篇 rt-thread------串口V1版本&#xff08;一&#xff09;配置 rt-thread------串口V1版本&#xff08;二&#xff09;发送篇 文章目录 系列文章目录一、串口的接收中断接收DMA接收 一、串口…

从一次netty分享漫谈

从一次netty分享漫谈 1.前言 上周五&#xff0c;笔者所在的开发小组&#xff0c;组织了一场分享&#xff0c;内容是netty的入门。笔者所在的团队&#xff0c;基本上就是在各条业务线中活蹦乱跳&#xff0c;有经验的看官&#xff0c;到这里已经可以给出分享效果的总体预测&…

Gradle 各个版本下载

每次都要找下载地址&#xff0c;还是记录一下好找点。 http://services.gradle.org/distributions

Unreal 5 官方在Niagara里模拟大型群体笔记

官方视频地址&#xff1a;https://www.bilibili.com/video/BV1FX4y1T7z2/ 如果需要&#xff0c;请查看官方视频。 性能测试 在讲解Niagara之前&#xff0c;视频首先做了一个性能测试&#xff0c;首先放置了100个AI角色&#xff0c;可以想目标角色移动的ai&#xff0c;然后测试…

C语言:猜凶手

题目&#xff1a; 日本某地发生了一件谋杀案&#xff0c;警察通过排查确定杀人凶手必为4个嫌疑犯的一个。 以下为4个嫌疑犯的供词: A说&#xff1a;不是我。 B说&#xff1a;是C。 C说&#xff1a;是D。 D说&#xff1a;C在胡说 已知3个人说了真话&#xff0c;1个人说的是假话。…

山西电力市场日前价格预测【2023-07-03】

日前价格预测 预测明日&#xff08;2023-07-03&#xff09;山西电力市场全天平均日前电价为333.50元/MWh。其中&#xff0c;最高日前电价为398.66元/MWh&#xff0c;预计出现在15: 15。最低日前电价为280.73元/MWh&#xff0c;预计出现在24: 00。 以上预测仅供学习参考&#x…

Spring第一讲:Spring基础概念和环境搭建

一、Spring是什么 Spring 是 Java EE 编程领域的一款轻量级的开源框架&#xff0c;由被称为“Spring 之父”的 Rod Johnson 于 2002 年提出并创立&#xff0c;它的目标就是要简化 Java 企业级应用程序的开发难度和周期。 Spring 自诞生以来备受青睐&#xff0c;一直被广大开发…

二叉树各种函数的实现

如果你觉得迷茫&#xff0c;那就尽可能选择比较困难的路。 目录 前言&#xff1a; &#x1f340;一.通过前序遍历创建二叉树 &#x1f341;二.二叉树的四种遍历 &#x1f342;1.二叉树的前序遍历 &#x1f33c;2.二叉树的中序遍历 &#x1f34c;3.二叉树的后序遍历 …

Mac VSCode配置运行单个C++文件

题外话&#xff1a;VSCode一键整理代码快捷键&#xff1a;ShiftoptionF 方法一&#xff1a;命令行直接编译 g -o 想创建的可执行文件名 ./cpp文件名 ./可执行文件名 以test.cpp为例&#xff0c;我创建的可执行文件名为test&#xff0c;运行结果如下&#xff1a; 方法二&#…

SpringCloud-Nacos配置管理

文章目录 Nacos配置管理统一配置管理在nacos中添加配置文件从微服务拉取配置 配置热更新方式一方式二 配置共享1&#xff09;添加一个环境共享配置2&#xff09;在user-service中读取共享配置3&#xff09;运行两个UserApplication&#xff0c;使用不同的profile3&#xff09;运…

React教程(由浅到深)

文章目录 1. 基本语法1.1 初体验Hello React1.2 JSX语法的基本使用1.2.1 语句与表达式说明 1.3. React面向组件编程1.3.1 函数组件与类组件 1.4 组件实例的三大特性1.4.1 state数据存储状态1.4.2 props的使用1.4.2.1基本使用1.4.2.2 做限制类型&#xff0c;默认值使用1.4.2.3 简…

2、boostrap 多数据类型表单

fileinput 视频图片文本数据表单 插件下载地址&#xff1a;https://github.com/kartik-v/bootstrap-fileinput/ 1、多类型数据from测试 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</tit…

Jeston Xavier NX 模块将系统迁移到NVME存储

大家好&#xff0c;我是虎哥&#xff0c;最近完成了自己设计的第一个Xavier NX的载板设计和打样&#xff0c;虽然还有一些小的不完善的地方&#xff0c;但是可以正常使用&#xff0c;这里记录和分享一下我自己设计的载板上如何实现系统迁移。 我自己使用SDK Manager 安装了所有…