ETL处理过程中,经常需要进行文件校验,如文件级校验、记录级校验,需要保存文件的基本信息,文件名、文件大小、数据日期等,使用Pro*C的一种方法如下:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <limits.h> #include <sqlda.h> #include <sqlcpr.h> /*定义数据库连接信息*/ #define USERNAME "masaetl" #define PASSWORD "masaetl" #define ORACLESID "DWDB2" /*定义数据存放目录,这些目录是链接文件的目录*/ char data_dir[5][64]={ "/ETL_FS/etlfs/interface/boss/input/day_full", "/ETL_FS/etlfs/interface/boss/input/day_incr", "/ETL_FS/etlfs/interface/boss/input/oth_full", "/ETL_FS/etlfs/interface/boss/input/oth_incr", "/ETL_FS/etlfs/interface/kf_data/link" }; /*定义处理日期,内部链接的静态变量*/ static char filedate[9]; /*调试代码时使用*/ #ifndef DEBUG #define DEBUG // 定义调试开关 #endif /*SQL语句返回值定义*/ /*定义返回值,成功为0,错误<0,警告>0 */ #define SQLCODE sqlca.sqlcode /*SQL语句返回错误解释 */ #define SQLERRMC sqlca.sqlerrm.sqlerrmc /*包含数据库信息*/ EXEC SQL INCLUDE sqlca; EXEC SQL INCLUDE sqlda; /*SQL语句返回值定义*/ /*定义返回值,成功为0,错误<0,警告>0*/ #define SQLCODE sqlca.sqlcode /*SQL语句返回错误解释*/ #define SQLERRMC sqlca.sqlerrm.sqlerrmc void sqlerror(); /*处理SQL错误*/ int ConnectDataBase(); /*链接数据库*/ void DisConnectDataBase(); /*断开数据库连接*/ char *getYestDate(char *szDate); /*得到前一天的日期,格式"YYYYMMDD"*/ char *getFileName(const char *szFilePath,char *szFileName); /*从字符串中得到文件名*/ /************************************** *** 功能: 提取运行在数据库级报错信息 *** 输入变量: *** 输出变量: ***************************************/ void sqlerror() { /*为了避免错误处理时发生死循环,应给出此说明*/ EXEC SQL WHENEVER SQLERROR CONTINUE; printf("\n Oracle error detected: "); printf("\n%s",SQLERRMC); /*错误信息*/ /*断开数据库链接*/ EXEC SQL ROLLBACK WORK RELEASE; exit(1); } /************************************** *** 功能: 连接数据库 *** 输入变量: *** 输出变量: -1 连接数据库失败 0 成功 ***************************************/ int ConnectDataBase() { EXEC SQL BEGIN DECLARE SECTION; char username[8]; char password[11]; char oraclesid[7]; EXEC SQL END DECLARE SECTION; strcpy(username,USERNAME); /*用户名*/ //username.len=strlen(username.arr); strcpy(password,PASSWORD); /*密码*/ //password.len=strlen(password.arr); strcpy(oraclesid,ORACLESID); /*Oralce SID*/ //oraclesid.len=strlen(oraclesid.arr); /*链接数据库*/ EXEC SQL CONNECT :username IDENTIFIED BY :password USING :oraclesid; if( SQLCODE ) { return -1; } return 0; } /************************************** *** 功能: 断开数据库连接 *** 输入变量: *** 输出变量: ***************************************/ void DisConnectDataBase() { /*断开连接*/ EXEC SQL ROLLBACK WORK RELEASE; exit(0); } /*************************************** ** 功能 : 得到前一天的日期 *** 输入变量: *** 输出变量: ****************************************/ char *getYestDate(char *szDate) { time_t yest; struct tm ptime={'\0'}; char szChar[5]; //若输入的参数为空,默认提取系统前一天的日期 if ( *szDate =='\0' ){ yest=time(NULL)-(time_t)(60*60*24); strftime(szDate,9,"%Y%m%d",localtime(&yest)); return szDate; } //提取年 memset(szChar,0,sizeof(szChar)); strncpy(szChar,szDate,4); ptime.tm_year=atoi(szChar)-1900; //提取月 memset(szChar,0,sizeof(szChar)); strncpy(szChar,szDate+4,2); ptime.tm_mon=atoi(szChar)-1; //提取日 memset(szChar,0,sizeof(szChar)); strncpy(szChar,szDate+6,2); ptime.tm_mday=atoi(szChar); yest=mktime(&ptime)-(time_t)(60*60*24); strftime(szDate,9,"%Y%m%d",localtime(&yest)); return szDate; } /*************************************** ** 功能 : 从文件路径中得到文件名称(去掉前面的路径) *** 输入变量:文件路径 *** 输出变量:文件名 ****************************************/ char *getFileName(const char *szFilePath,char *szFileName) { char *szPtr; const char separator='/'; /*定义分隔符*/ szPtr=strrchr(szFilePath,separator); /*查找最后一个子串*/ if ( szPtr ){ szFileName=szPtr+1; } #ifdef DEBUG printf("文件名称为: [%s]",szFileName); #endif return szFileName; } /*************************************** ** 功能 : 主程序 ****************************************/ int main( void ) { int i=0; char *szOrderId; char pFileName[128]; char *filename; //文件名 char szDate[15]; //日期 "yyyymmddhh24miss" time_t file_mtime; //文件时间 struct stat st; struct dirent *dirp; DIR *pDirectory; /*定义数据库变量*/ EXEC SQL BEGIN DECLARE SECTION; char file_date[9]; //文件日期 long orderid; //序号(接口编号) char file_name[30]; //文件名称 long file_size; //文件大小 char file_create_date[15]; //文件最后修改的时间 EXEC SQL END DECLARE SECTION; /*链接数据库*/ if( ConnectDataBase()<0 ){ printf("连接数据失败.\n"); } /*得到处理日期*/ getYestDate(filedate); strcpy(file_date,filedate); #ifdef DEBUG printf("处理日期: [%s].\n",file_date); #endif /*删除当日已统计数据*/ EXEC SQL DELETE FROM MASAETL.ETL_LINK_FILE WHERE FILEDATE=:file_date; /*处理执行SQL异常*/ if ( 1403!=SQLCODE && 0!=SQLCODE ){ #ifdef DEBUG printf("删除当日统计数据失败,原因为:[%d]:[%s]\n",SQLCODE,SQLERRMC); #endif EXEC SQL ROLLBACK; DisConnectDataBase(); exit(1); } /*提交删除信息*/ EXEC SQL COMMIT; /*循环处理目录下的文件*/ for( i=0; i<5; i++) //while ( *data_dir[i++] ) { if ( (pDirectory=opendir(data_dir[i]))==NULL ){ printf("打开目录[%s]失败.\n",data_dir[i]); continue; } while( (dirp=readdir(pDirectory))!=NULL ){ if (strcmp(dirp->d_name,".")==0 || strcmp(dirp->d_name,"..")==0) { continue; } sprintf(pFileName,"%s/%s",data_dir[i],dirp->d_name); #ifdef DEBUG printf("文件名为: [%s].\n",dirp->d_name); #endif if( stat(pFileName,&st) <0 ){ printf("读文件[%s]到文件结构失败.\n",dirp->d_name); continue; } /*得到文件最后修改时间*/ file_mtime=st.st_mtime; strftime(szDate,15,"%Y%m%d%H%S",localtime(&file_mtime)); strcpy(file_create_date,szDate); /*得到文件大小*/ file_size=st.st_size; /*得到文件名*/ //getFileName(szFileName,filename); strcpy(file_name,dirp->d_name); /*得到接口序号*/ strncpy(szOrderId,file_name+1,5); szOrderId[6]='\0'; orderid=atol(szOrderId); /*将文件信息入库*/ EXEC SQL INSERT INTO MASAETL.ETL_LINK_FILE(FILEDATE,ORDER_ID,FILENAME,FILECREATEDATE,FILESIZE) VALUES(:file_date, :orderid, :file_name,TO_DATE( :file_create_date,'YYYYMMDDHH24MISS'), :file_size); /*处理执行SQL异常*/ if ( SQLCODE ){ #ifdef DEBUG printf("向数据库中写入文件信息失败,原因为:[%d]:[%s]\n",SQLCODE,SQLERRMC); #endif EXEC SQL ROLLBACK; continue; } /*提交录入信息*/ EXEC SQL COMMIT; } /*关闭目录*/ closedir(pDirectory); } /*断开数据库连接*/ DisConnectDataBase(); return 0; }