服务器 频道

用C++ 产生 SQL*Loader 各类文件

  【IT168服务器学院】1.前言
  
  目前,我国许多单位MIS系统建立在微机PC或基于NovellNetWare局域网环境中,数据库和开发工具采用Foxpro2.5forDOS或Foxpro2.5forWindows,以dbf文件为数据组织管理手段,随着系统的不断扩大和实际应用的需要,不少单位已开始采用大型数据库Oracle。在MIS从Foxpro升级到大型数据库Oracle过程中,将Foxpro的dbf文件通过Oracle工具SQL*Loader加载到Oracle数据库中是一项非常重要的工作。一般用SQL*Loader加载的具体实施步骤是:
  
  *运行Foxpro,打开数据库,将dbf文件拷贝为SDF格式的文本文件
  
  *根据dbf文件结构,产生建立Oracle表(CREATETABLE)的SQL语句
  
  *登录Oracle,运行产生Oracle表(CREATETABLE)的SQL语句
  
  *根据dbf文件结构,产生SQL*Loader的控制文件
  
  *运行SQL*Loader,加载数据
  
  用手工方法产生CREATETABLE的SQL语句,特别是产生SQL*Loader控制文件时,POSITION起始、结束位置经常弄错,当需要加载大量的数据时,不但烦琐,而且效率比较低。我们在实践中利用BorlandC++5.0编制了一个C++实用程序load.cpp,自动产生SQL*Loader的数据文件、控制文件和产生CREATETABLE的SQL语句。运用load,我们只需:
  
  *load<数据库名>
  
  *登录Oracle,运行产生Oracle表(CREATETABLE)的SQL语句
  
  *运行SQL*Loader,加载数据
  
  在实践中,我们通过这种方法,在实现从Foxpro到OracleforDigitalUNIX+中文Windows95的client/server平台的数据加载过程中提高了效率。
  
  2.Foxpro中dbf文件结构
  
  dbf文件由文件头和文件记录组成,其中文件头又由数据库说明和字段说明组成。数据库说明由32个字节组成,各字节含义见表一:
  
  字节
  含义
  0
  数据库文件标志有无备注型字段(03H无)
  1-3
  最后一次修改日期
  4-7
  文件记录数
  8-9
  文件头长度
  10-11
  记录长度
  12-31
  未用
  
  表一
  
  字段说明由若干个32字节组成,每32字节说明一个字段,各字节含义见表二:
  
  字节
  含义
  0-10
  字段名
  11
  字段类型
  12-15
  该字段在文件首记录中的地址
  16
  字段长度
  17
  小数位数
  18-31
  未用
  
  表二
  
  文件记录以ASCII形式存储,每条记录以空格(20H)开头,该空格用来作删除标志用。
  
  3.建立对应Foxpro的Oracle表的SQL语句
  
  Foxpro和Oracle对应的数据类型的描述见表三:
  
  Foxpro
  Oracle
  Character(n)
  char(n)varchar2(n)
  Number(n,m)
  number(n-1,m)m<>0
  number(n,m)m=0
  Float(n,m)
  
  Logical
  char(1)
  DATE
  DATE
  
  三
  
  【注】:
  
  *不考虑完整性约束,同时对于TABLESPACE及STORAGE存储参数取缺省值。
  
  *对于数字型字段,n表示数字的宽度,在Foxpro中包含小数点位置,而在Oracle中不包含。
  
  *对于Foxprological型字段类型,由于Oracle中没有相应的逻辑型变量,故将其转换为字符类型。
  
  *暂且不考虑memo、general、picture字段的转换。
  
  4.SQL*Loader控制文件的建立
  
  控制文件为SQL*Loader的核心文件,与Foxpro字段对应关系为表四:Foxpro数据类型
  
  控制文件语句对应的格式
  
  Character(n)
  CHAR
  Number(n,m)
  Float(n,m)
  DECIMALEXTERNALNULLIF<field>=BLANKS(m<>0)
  
  INTEGEREXTERNALNULLIF<field>=BLANKS(m=0)
  Logical
  CHAR
  DATE
  DATE"YYYYMMDD"NULLIF<field>=BLANKS
  
  四
  
  以下是用BorlandC++5.0在中文Windows95下编制的产生CREATETABLESQL语句和产生SQL*Loader数据文件、控制文件的源程序load.cpp。
  
  #include<stdio.h>
  #include<stdlib.h>
  #include<iostream.h>
  #include<fstream.h>
  #include<string.h>
  #include<math.h>
  #defineMAX_ROW_LENGTH1200
  #defineMAX_FIELD_NUMBER30
  typedefstructhead//dbf头文件结构
  {unsignedcharmask;
  unsignedchardate[3];
  unsignedlongrecord_num;
  unsignedshortinthead_length;
  unsignedshortintfield_length;
  }HEAD;
  
  typedefstructfield//dbf字段结构
  {unsignedcharname[11];
  unsignedchartype;
  unsignedlongadd;
  unsignedcharlength;
  unsignedchardec;
  }FIELD;
  
  intmain(intargc,char**argv)
  {charbuf[MAX_ROW_LENGTH],dbf[40],*sqlload;
  unsignedinti,field_num;
  HEAD*dbfhead;
  FIELDdbffield[MAX_FIELD_NUMBER];
  FILE*fout,*fp;
  
  if(argc!=2)
  {cout<<"Usage:loaddbfile"<<endl;
  return-1;
  }
  
  sqlload=newchar(40);
  dbfhead=newHEAD;
  strcpy(buf,"");
  
  strcpy(dbf,argv[1]);
  strcat(dbf,".dbf");
  if((fp=fopen(dbf,"rb"))==NULL)
  {cout<<"Cannotopenfile"<<dbf<<endl;
  return-1;
  }
  fseek(fp,0,SEEK_SET);
  fread(dbfhead,sizeof(HEAD),1,fp);//读dbf头文件信息
  
  field_num=(dbfhead->head_length-1)/32-1;//字段个数
  
  for(i=0;i<field_num;i++)
  {fseek(fp,32*(i+1),SEEK_SET);
  fread(&dbffield[i],sizeof(FIELD),1,fp);//读dbf结构信息
  }
  //产生SQL*Loader控制文件
  strcpy(sqlload,argv[1]);
  strcat(sqlload,".ctl");
  if((fout=fopen(sqlload,"w"))==NULL)
  {cout<<"Cannotopenfile"<<sqlload<<endl;
  return-1;
  }
  fprintf(fout,"LOADDATA\n");
  fprintf(fout,"INFILE''%s.txt''\n",argv[1]);
  fprintf(fout,"INTOTABLE%s(\n",argv[1]);
  
  for(i=0;i<field_num;++i)
  {fprintf(fout,"%11sPOSITION(%d:%d)",dbffield[i].name,
  dbffield[i].add,dbffield[i].add+dbffield[i].length-1);
  switch(dbffield[i].type)
  {case''C'':
  case''L''://字符型/逻辑型
  fprintf(fout,"CHAR");
  break;
  case''N'':
  if(dbffield[i].dec==0)//整数型
  fprintf(fout,"INTEGEREXTERNALNULLIF%s=BLANKS",
  dbffield[i].name);
  else//实数型
  fprintf(fout,"DECIMALEXTERNALNULLIF%s=BLANKS",
  dbffield[i].name);
  break;
  case''D''://日期型
  fprintf(fout,"DATE''YYYYMMDD''NULLIF%s=BLANKS",
  dbffield[i].name);
  break;
  default:
  break;
  }
  if(i<field_num-1)
  fprintf(fout,",\n");
  }
  fprintf(fout,")\n");
  fclose(fout);
  
  //产生CREATETABEL.的SQL语句
  strcpy(sqlload,argv[1]);
  strcat(sqlload,".sql");
  if((fout=fopen(sqlload,"w"))==NULL)
  {cout<<"Cannotopenfile"<<sqlload<<endl;
  return-1;
  }
  fprintf(fout,"createtable%s(\n",argv[1]);
  for(i=0;i<field_num;i++)
  {fprintf(fout,"%11s",dbffield[i].name);
  switch(dbffield[i].type)
  {case''C''://字符型
  fprintf(fout,"CHAR(%d)",dbffield[i].length);
  break;
  case''L''://逻辑型
  fprintf(fout,"CHAR(1)");
  break;
  case''N''://数字型
  if(dbffield[i].dec==0)
  fprintf(fout,"NUMBER(%d)",dbffield[i].length);
  else
  fprintf(fout,"NUMBER(%d,%d)",
  dbffield[i].length-1,dbffield[i].dec);
  break;
  case''D''://日期型
  fprintf(fout,"DATE");;
  break;
  default:
  break;
  }
  if(i<field_num-1)
  fprintf(fout,",\n");
  }
  fprintf(fout,")\n");
  fclose(fout);
  
  //产生SQL*Loader数据文件
  strcpy(sqlload,argv[1]);
  strcat(sqlload,".txt");
  if((fout=fopen(sqlload,"w"))==NULL)
  {cout<<"Cannotopenfile"<<sqlload<<endl;
  return-1;
  }
  fseek(fp,dbfhead->head_length,SEEK_SET);
  
  for(i=0;i<dbfhead->record_num;i++)
  {fread(buf,dbfhead->field_length,1,fp);
  buf[dbfhead->field_length]=''\0'';
  fprintf(fout,"%s\n",buf+1);//skip记录首字节(删除标志)
  }
  fclose(fout);
  fclose(fp);
  
  deletesqlload;
  return0;
  }
0
相关文章