06年毕业,转眼也学习oracle 大概1年半得时间了,上次看到有人说可以恢复没有备份得truncate表,其实原理就是抽取数据得方式,因此自己也想写一个.通过几天得努力,终于写了一个初版 ,目前该版本支持得数据类型有: varchar2 ,number ,date 类型, 因为我看到得大部分系统表设计只涉及这些列类型(blob 除外 ,这个以后有空再写),现在只支持行迁移,不支持行连接(行连接我觉得一个设计好得系统不应该出现,可以使用大得block_size来避免,或做成多张表,因此也就没有花精力来做行连接),我这边程序测试得数据库版本为9201,数据块得大小为8k,其他数据块版本得,数据块情况没有测试过.

测试如下:建表

create table test_table

as

select * from all_objects;

SQL> desc test_table

名称                                      是否为空? 类型

----------------------------------------- -------- ----------------------------

OWNER                                     NOT NULL VARCHAR2(30)

OBJECT_NAME                               NOT NULL VARCHAR2(30)

SUBOBJECT_NAME                                     VARCHAR2(30)

OBJECT_ID                                 NOT NULL NUMBER

DATA_OBJECT_ID                                     NUMBER

OBJECT_TYPE                                        VARCHAR2(18)

CREATED                                   NOT NULL DATE

LAST_DDL_TIME                             NOT NULL DATE

TIMESTAMP                                          VARCHAR2(19)

STATUS                                             VARCHAR2(7)

TEMPORARY                                          VARCHAR2(1)

GENERATED                                          VARCHAR2(1)

SECONDARY                                          VARCHAR2(1)

SQL> select count(*) from test_table;

COUNT(*)

----------

29280

SQL> set linesize 150

SQL> select * from test_table where rownum<10;

OWNER                          OBJECT_NAME                    SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE        CREATED

------------------------------ ------------------------------ ------------------------------ ---------- -------------- ------------------ ----------

LAST_DDL_T TIMESTAMP           STATUS  T G S

---------- ------------------- ------- - - -

SYS                            /1005bd30_LnkdConstant                                             17286                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:38:40 VALID   N N N

SYS                            /10076b23_OraCustomDatumClosur                                      7559                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:38:11 VALID   N N N

SYS                            /10297c91_SAXAttrList                                              22542                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:39:39 VALID   N N N

OWNER                          OBJECT_NAME                    SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE        CREATED

------------------------------ ------------------------------ ------------------------------ ---------- -------------- ------------------ ----------

LAST_DDL_T TIMESTAMP           STATUS  T G S

---------- ------------------- ------- - - -

SYS                            /103a2e73_DefaultEditorKitEndP                                     13614                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:38:28 VALID   N N N

SYS                            /1048734f_DefaultFolder                                            22345                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:39:31 VALID   N N N

SYS                            /10501902_BasicFileChooserUINe                                     10173                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:38:19 VALID   N N N

OWNER                          OBJECT_NAME                    SUBOBJECT_NAME                  OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE        CREATED

------------------------------ ------------------------------ ------------------------------ ---------- -------------- ------------------ ----------

LAST_DDL_T TIMESTAMP           STATUS  T G S

---------- ------------------- ------- - - -

SYS                            /105072e7_HttpSessionBindingEv                                     22747                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:47:57 VALID   N N N

SYS                            /106ba0a5_ArrayEnumeration                                         22797                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:48:02 VALID   N N N

SYS                            /106faabc_BasicTreeUIKeyHandle                                      9849                JAVA CLASS         31-3月 -07

31-3月 -07 2007-03-31:00:38:18 VALID   N N N

已选择9行。

SQL> spool off

程序抽取出来得数据:

SYS,/1005bd30_LnkdConstant,null,17286,null,JAVA CLASS,2007-03-31 00:38:40,2007-03-31 00:38:40,2007-03-31:00:38:40,VALID,N,N,N

SYS,/10076b23_OraCustomDatumClosur,null,7559,null,JAVA CLASS,2007-03-31 00:38:11,2007-03-31 00:38:11,2007-03-31:00:38:11,VALID,N,N,N

SYS,/10297c91_SAXAttrList,null,22542,null,JAVA CLASS,2007-03-31 00:39:39,2007-03-31 00:42:08,2007-03-31:00:39:39,VALID,N,N,N

SYS,/103a2e73_DefaultEditorKitEndP,null,13614,null,JAVA CLASS,2007-03-31 00:38:28,2007-03-31 00:38:28,2007-03-31:00:38:28,VALID,N,N,N

SYS,/1048734f_DefaultFolder,null,22345,null,JAVA CLASS,2007-03-31 00:39:31,2007-03-31 00:39:34,2007-03-31:00:39:31,VALID,N,N,N

SYS,/10501902_BasicFileChooserUINe,null,10173,null,JAVA CLASS,2007-03-31 00:38:19,2007-03-31 00:38:19,2007-03-31:00:38:19,VALID,N,N,N

SYS,/105072e7_HttpSessionBindingEv,null,22747,null,JAVA CLASS,2007-03-31 00:39:49,2007-03-31 00:48:00,2007-03-31:00:47:57,VALID,N,N,N

SYS,/106ba0a5_ArrayEnumeration,null,22797,null,JAVA CLASS,2007-03-31 00:39:52,2007-03-31 00:48:07,2007-03-31:00:48:02,VALID,N,N,N

SYS,/106faabc_BasicTreeUIKeyHandle,null,9849,null,JAVA CLASS,2007-03-31 00:38:18,2007-03-31 00:38:18,2007-03-31:00:38:18,VALID,N,N,N

..............................

..............................

RMAN920,XCF_P,null,30396,30396,INDEX,2007-10-06 10:12:55,2007-10-06 10:12:55,2007-10-06:10:12:55,VALID,N,N,N

RMAN920,XCF_U1,null,30397,30397,INDEX,2007-10-06 10:12:55,2007-10-06 10:12:55,2007-10-06:10:12:55,VALID,N,N,N

RMAN920,XDF,null,30412,30412,TABLE,2007-10-06 10:12:56,2007-10-06 10:12:57,2007-10-06:10:12:56,VALID,N,N,N

RMAN920,XDF_I_DF_KEY,null,30415,30415,INDEX,2007-10-06 10:12:57,2007-10-06 10:12:57,2007-10-06:10:12:57,VALID,N,N,N

RMAN920,XDF_I_HANDLE_STATUS,null,30416,30416,INDEX,2007-10-06 10:12:57,2007-10-06 10:12:57,2007-10-06:10:12:57,VALID,N,N,N

RMAN920,XDF_P,null,30413,30413,INDEX,2007-10-06 10:12:56,2007-10-06 10:12:56,2007-10-06:10:12:56,VALID,N,N,N

RMAN920,XDF_U1,null,30414,30414,INDEX,2007-10-06 10:12:56,2007-10-06 10:12:56,2007-10-06:10:12:56,VALID,N,N,N

共29280条数据

行迁移测试

有表发生了行迁移,查询出来得数据为:

.............

rrrrrrr .....其实这边有200多个r,就省略了

rrrrrrr.......

rrrrrrr......

rrrrrrr

rrrrrrr

rrrrrrr

b111

b111

b222

范    581 行

鑫3    582行

........

.......

........ 共1722行

程序抽取得数据为:

........

........

........

b111,

b111,

b222,

范,      1721行

鑫3,    1722行

可以看到 ,oracle 在做全表扫描得时候 ,是忽略行迁移得 ,即一直扫描行,并不会碰到行迁移,就会去读取目标行,因为目标行总会扫描到.

我得程序是顺序扫描得,当发生行迁移时,会去读目标行 ,所以抽取出来得数据不一样,程序抽取出来得数据时严格意义上得顺序得.

程序源代码如下:

#include

#include

#include

#include

//用于判断存储是大端方式还是小端方式

#define LITTLE  0

#define BIG  1

//定义block得大小为8k

#define BLOCK_SIZE 8

//itl 事务槽字节数,每个事务槽占用 24 个字节

#define ITL_SIZE 24

/*

整个block可以分为:block head+ data+tail

其中block head 又可分为:

1. block head 的基本信息 --即struct head  共占用44个字节

2. 具体的事务槽信息,具体大小不确定,计算方法为: head->itc*ITL_SIZE

3. 行字典 具体大小也不固定 ,根据行的多少来计算字节数

tail 在块的末尾: 共占用4个字节

可以看到:在block的中,具体的事务槽字节数目和行字典的字节数目都是会动态增长的,比如说对块的DML并发数量的增加,

会引起事务槽的增加,行的增加会影响行字典的增加,所以这就是为什么oracle 会从尾部开始插入行.如果将行从在前面开始

增加,势必会造成字符串的移动

*/

//head 结构用于对block的基本描述

struct head

{

unsigned char block_type;   //一个字节

unsigned char unknown1[3];  // 3个字节

int rdba;    //4个字节

int scn_front; //4个字节

unsigned short int scn_back; //2个字节

unsigned char seq;//对于该块进行的DML操作时同一个SCN号,seq次数会增加

unsigned char flg;

unsigned short int chkval; //校验所用

char unknown2[6];

unsigned int obj;

int csc;

int unused;

unsigned char itc;  //事务槽的数目

char unknown3[7];

};

//row_dic结构用于对row_dictionary的描述

struct row_dic

{

unsigned char flag;

unsigned char ntab;

unsigned short int pre_nrows;

short int frre;

unsigned short int fsbo;

unsigned short int fseo;

unsigned short int avsp;

unsigned short int tosp;

//row_dictionary

unsigned short int offs;

unsigned short int nrows;

//行地址有可能为负,即ffff,-1,代表被删除的最后一行

short int pri[256]; //这里其实并不知道具体有多少行,但并不影响读取数据,这边是根据指针转换读取数据的

};

char col_type[255][20]={"varchar2","varchar2","varchar2","number","number",

"varchar2", "date", "date", "varchar2", "varchar2",

"varchar2", "varchar2", "varchar2"};

char support_type[3][20]={"varchar2","number","date"};

int real_col_cnt;

void parseNumber(unsigned char * head,int col_size,char *result);

void formatNumber(char *tmp_num1 ,int num_idx,int exp ,char *result);

int testLittleOrBig();

int vertify(int argc ,char **argv);

void parseRowMovment(unsigned char *p);

void parseRow(int fileid ,int blockid ,int rownum);

void parseDate(unsigned char *p,char *date);

/*

程序编制者: fxyj_2008  : 范鑫

程序版本: ver 1.0 试用版

*/

void main(int argc, char *argv[])

{

int fp;

unsigned char *p;

int i=0;

int temp;

int row;

int col;

unsigned int objectid;

char str[1024*BLOCK_SIZE+1];

struct head *phead;

struct row_dic *prow_dic;

int offset;

unsigned char *idx;

int col_cnt;

int col_size;

unsigned short int var_size;

char num[42];

long size;

long block_num;

char varchar2[4000];

char date[20];

/*

每个行由以下几个组成:

1. fb 占一个字节(行的相关信息)

2. lb 事务槽的指针

3. 列的数目

4. 列数据,列数据具体组成: 列长度+列数据

*/

unsigned char fb;

int lastpos=0;

str[1024*8]='\0';

if(argc<2)

{

printf("必须输入列得类型");

return;

}

if(vertify(argc,argv)==-1)

return;

else

{

for(i=1;i

strcpy(col_type[i-1],argv);

i=0;

}

/*

printf("enter the object id :");

scanf("%d",&objectid);

*/

objectid=30552;

real_col_cnt=argc-1;

if((fp=open("TST.DBF",O_RDONLY))==1)

return;

lseek(fp,0,SEEK_END);

size=tell(fp);

block_num=size/1024/BLOCK_SIZE;

lseek(fp,9*1024*BLOCK_SIZE,SEEK_SET);

for(int n=9;n

{

read(fp,str,sizeof(char)*1024*BLOCK_SIZE);

p=(unsigned char *)str;

phead=(struct head *)p;   //将首地址转换为head 指针类型

prow_dic=(struct row_dic *)(p+sizeof(head)+ITL_SIZE*phead->itc); //获取行字典的首地址

/*获取行字典的偏移地址,在行字典中存放的行的位置其实是个偏移地址,偏移地址=44+事务槽占用的字节数据,所以每次有事务

槽扩展的时候行字典中行的位置都要做相应改变,以保证偏移地址的正确性

*/

offset=sizeof(head)+ITL_SIZE*phead->itc;

//由于文件系统提供的接口函数存在BUG ,主要是windows平台,所以这边需要写tell(fp);

lastpos=tell(fp);

if(phead->block_type==6)

{

// printf("%d\n",phead->obj);

//continue;

if(phead->obj!=objectid)

continue;

for(row=0;rownrows;row++)

{

// addr=(unsigned char *)(p+ps->pri[row]+92);

//行被删除标志,行字典中的行相对偏移地址

if((prow_dic->pri[row]nrows) || (prow_dic->pri[row]==-1))

{

continue;

}

fb=*(p+prow_dic->pri[row]+offset);

//行被删除标志,即fb的第5个字节为1,代表'D'

if((fb>>4)&0x01==1)

continue;

//如果fb的第6个字节为1,第3,4个字节为1,即H标志为1;F,L为1的情况下,表示行正常

if(fb==0x2c)

{

col_cnt=*(p+prow_dic->pri[row]+offset+2);

idx=p+prow_dic->pri[row]+offset+2+1;

for(col=0;col

{

col_size=*(idx);

idx=idx+1;

if(col_size==0xff)  //FF 代表该值为null

{

printf("null");

if(col!=col_cnt-1)

printf(",");

continue;

}

if(strcmp(col_type[col],"varchar2")==0)

{

if(col_size==0xfe)   //如果首字符大小是0xfe ,那么这个字符的大小用后两个字节表示

{

var_size=*((unsigned short int *)idx); //字符串真实大小

idx=idx+2;

col_size=var_size;

}

for(temp=0;temp

varchar2[temp]=*(idx+temp);

varchar2[temp]='\0';

printf("%s",varchar2);

}

else if(strcmp(col_type[col],"number")==0)

{

parseNumber(idx,col_size,num);

printf("%s",num);

}

else if(strcmp(col_type[col],"date")==0)

{

parseDate(idx,date);

printf("%s",date);

}

if(col!=col_cnt-1)

printf(",");

idx=idx+col_size;

}

if(col_cnt

{

for(temp=real_col_cnt-col_cnt;temp>0;temp--)

printf(",");

}

printf("\n");

}

//如果fb的第6个字节为1,第3,4个字节为0,即H标志为1;F,L为0的情况下,表示发生了行迁移,此时读取nrid

else if(fb==0x20)

{

parseRowMovment(p+prow_dic->pri[row]+offset+2+1);

continue;

}

else if((fb>>5)&0x01==0)   //如果fb标志得H标志为0,表示是行迁移或行连接得数据,不处理

{

continue;

}

//如果fb标志得H标志为1,F标志为1 ,L 标志为0  ,表示发生了行连接,不处理

else if(((fb>>5)&0x01==1)&&((fb>>3)&0x01==1)&&((fb>>2)&0x01==0))

{

printf("系统暂不支持行连接\n");

continue;

}

}

}

}

close(fp);

}

int vertify(int argc ,char **argv)

{

int i;

int j;

int flag=-1;

for(i=1;i

{

for(j=0;j<3;j++)

if(strcmp(*(argv+i),*(support_type+j))==0)

{

flag=1;

break;

}

if(flag==-1)

return -1;

else

flag=-1;

}

return 1;

}

//用于测试存储方式 ,是大端存储还是小端存储

int testLittleOrBig()

{

int test=0x12345678;

unsigned char *p;

p=(unsigned char *)&test;

if(*p==0x12)

return BIG;

else

return LITTLE;

}

void parseRow(int fileid ,int blockid ,unsigned short int rownum)

{

int fp;

unsigned char *p;

int i=0;

int temp;

int col;

char str[1024*BLOCK_SIZE+1];

struct head *phead;

struct row_dic *prow_dic;

int offset;

unsigned char *idx;

int col_cnt;

int col_size;

unsigned short int var_size;

char num[42];

char varchar2[4000];

char date[20];

unsigned char fb;

str[1024*8]='\0';

if ((fp=open("TST.DBF",O_RDONLY))==1)

return;

lseek(fp,blockid*1024*BLOCK_SIZE,SEEK_SET);

read(fp,str,sizeof(char)*1024*BLOCK_SIZE);

p=(unsigned char *)str;

phead=(struct head *)p;   //将首地址转换为head 指针类型

prow_dic=(struct row_dic *)(p+sizeof(head)+ITL_SIZE*phead->itc); //获取行字典的首地址

offset=sizeof(head)+ITL_SIZE*phead->itc;

fb=*(p+prow_dic->pri[rownum]+offset);

//行被删除标志,即fb的第5个字节为1,代表'D'

if((fb>>4)&0x01==1)

return;

//如果fb的第6个字节为0,第3,4个字节为1,即H标志为0;F,L为1的情况下,表示行正常

if(fb==0x0c)

{

col_cnt=*(p+prow_dic->pri[rownum]+offset+2);

//注意: 发生行迁移得时候 , 目的行存有原行得rowid,所以这边需要加6个字节

idx=p+prow_dic->pri[rownum]+offset+2+6+1;

for(col=0;col

{

col_size=*(idx);

idx=idx+1;

if(col_size==0xff)  //FF 代表该值为null

{

printf("null");

if(col!=col_cnt-1)

printf(",");

continue;

}

if(strcmp(col_type[col],"varchar2")==0)

{

if(col_size==0xfe)   //如果首字符大小是0xfe ,那么这个字符的大小用后两个字节表示

{

var_size=*((unsigned short int *)idx); //字符串真实大小

idx=idx+2;

col_size=var_size;

}

for(temp=0;temp

varchar2[temp]=*(idx+temp);

varchar2[temp]='\0';

printf("%s",varchar2);

}

else if(strcmp(col_type[col],"number")==0)

{

parseNumber(idx,col_size,num);

printf("%s",num);

}

else if(strcmp(col_type[col],"date")==0)

{

parseDate(idx,date);

printf("%s",date);

}

if(col!=col_cnt-1)

printf(",");

idx=idx+col_size;

}

if(col_cnt

{

for(temp=real_col_cnt-col_cnt;temp>0;temp--)

printf(",");

}

printf("\n");

}

//如果fb的第6个字节为0,第3,4个字节为1,0,即H标志为0;F为1 ,L为0的情况下,表示发生了行迁移中发生了行连接,行连接不处理

else if(((fb>>5)&0x01==0)&&((fb>>3)&0x01==1)&&((fb>>2)&0x01==0))

{

printf("行迁移中发生行连接,行连接暂不支持");

printf("\n");

return;

}

close(fp);

}

void parseRowMovment(unsigned char *p)

{

unsigned char rid[6];  //rowid,占6个字节 10个字节文件号+22个字节 blcokid+ 2个字节得行数

int fileid;

int blockid;

unsigned short int rownum;

int i=0;

unsigned  int tmp;

int flag;

flag=testLittleOrBig();

if(flag==LITTLE)

{

for(i=0;i<4;i++)

rid=p[3-i];

rid[4]=p[5];

rid[5]=p[4];

}

tmp=*((unsigned int *)(rid));

fileid=tmp>>22;

blockid=tmp&0x003fffff;

rownum=*((unsigned short int *)(rid+4));

parseRow(fileid,blockid,rownum);

}

/*

date 在磁盘中存储共占用7个字节 ,ixora 上面资料获取

byte 1: century + 100

byte 2: year + 100

byte 3: month

byte 4: day of month

byte 5: hour + 1

byte 6: minute + 1

byte 7: second + 1

*/

void parseDate(unsigned char *p,char *date)

{

//2008-01-01 12:01:01

//年

*date=(*p-100)/10+'0';        *(date+1)=(*(p)-100)%10+'0';

*(date+2)=(*(p+1)-100)/10+'0'; *(date+3)=(*(p+1)-100)%10+'0';

*(date+4)='-';

//月

*(date+5)=(*(p+2))/10+'0';    *(date+6)=(*(p+2))%10+'0';

*(date+7)='-';

//日

*(date+8)=(*(p+3))/10+'0';    *(date+9)=(*(p+3))%10+'0';

*(date+10)=' ';

//时

*(date+11)=(*(p+4)-1)/10+'0';    *(date+12)=(*(p+4)-1)%10+'0';

*(date+13)=':';

//分

*(date+14)=(*(p+5)-1)/10+'0';    *(date+15)=(*(p+5)-1)%10+'0';

*(date+16)=':';

//秒

*(date+17)=(*(p+6)-1)/10+'0';    *(date+18)=(*(p+6)-1)%10+'0';

*(date+19)='\0';

}

/*

number 表示方法

1bit符号位+7bit指数位    数据位(100进制表示)

对于正数:

1bit符号位为1,接下来的一个字节也为1

数据位-1=真实数据

对于0

首个字节为0x80 ,没有数据位

对于负数

1bit符号位为0

数据位为补码表示,真实数据为101-数据位

具体如下:

00-3E 表示: number <= -1--从3E开始递减 , 3E表示1

3F-7F 表示: -1 < number < 0 --从3F开始递增 ,3F表示0

可以看到,正数和负数的划分在于看第一个bit

81-C0 表示: 0 < number < 1  --从C0开始递减,C0表示0

C1-FF 表示:number >= 1 --从C1开始递增,C1表示1

*/

void parseNumber(unsigned char * head,int col_size,char *result)

{

unsigned char tmp;

int num_idx=0;

int value;

int exp=0;

int p;

char tmp_num1[42];

tmp=*head;

head=head+1;

int k;

k=(tmp&0x80)>>7;

//数据>=0

if (k==1)

{

if(tmp==0x80)

{

result[0]='0';

result[1]='\0';

return;

}

else

{

for (p=0;p

{

value=head[p]-1;

tmp_num1[num_idx]=value/10+'0';

tmp_num1[num_idx+1]=value%10+'0';

num_idx=num_idx+2;

}

tmp_num1[num_idx]='\0';

exp=tmp-0xc0;

formatNumber(tmp_num1,num_idx,exp,result);

return;

}

}

else  //数据<0

{

for (p=0;p

{

value=101-head[p];

tmp_num1[num_idx]=value/10+'0';

tmp_num1[num_idx+1]=value%10+'0';

num_idx=num_idx+2;

}

tmp_num1[num_idx]='\0';

exp=0x3e-tmp;

formatNumber(tmp_num1,num_idx,exp,result+1);

result[0]='-';

return;

}

}

void formatNumber(char *tmp_num1 ,int num_idx,int exp ,char *result)

{

int p=0;

char tmp_num2[42];

char prefix[40]="\0";

char post[40]="\0";

char const_c[]="0.";

if(exp>0)

{

if(2*exp==num_idx)

{

if(tmp_num1[0]=='0')

strcpy(result,tmp_num1+1);

else

strcpy(result,tmp_num1);

return;

}

else if(2*exp

{

for(p=0;p<2*exp;p++)

tmp_num2[p]=tmp_num1[p];

tmp_num2[p]='.';

for(;p

tmp_num2[p+1]=tmp_num1[p];

tmp_num2[num_idx+1]='\0';

if(tmp_num2[0]=='0')

strcpy(result,tmp_num2+1);

else

strcpy(result,tmp_num2);

return;

}

else

{

for(p=0;p

strcat(post,"00");

strcpy(tmp_num1+num_idx,post);

if(tmp_num1[0]=='0')

strcpy(result,tmp_num1+1);

else

strcpy(result,tmp_num1);

return;

}

}

else

{

if(exp==0)

{

strcpy(result,const_c);

strcpy(result+2,tmp_num1);

return;

}

else

{

for(p=0;p

strcat(prefix,"00");

strcpy(result,const_c);

strcpy(result+2,prefix);

strcpy(result+2+(exp*-1*2),tmp_num1);

return;

}

}

}

参考资料: 其中fb信息来自 grassbell 得 偷窥Data block 的物理结构,具体信息如下:

其中(摘自biti_rainy的关于block中数据的存储和重组的探究):

fb Flag Byte:

K = Cluster Key (Flags may change meaning if this is set to show HASH cluster)

C = Cluster table member

H = Head piece of row

D = Deleted row

F = First data piece

L = Last data piece

P = First column continues from previous piece

N = Last column continues in next piece

number 内部存储参考了 zhouwf 得部分章节

其他得基本都自己研究,具体研究方法其实也很简单

把数据块以16进制打印出来 ,然后用 alter system dump datafile N block M dump 出来 ,进行对比起来看

打印block 16进制得代码为,大家可以参考一下:

#include

#include

#include

char source[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

void main()

{

int fp;

unsigned char *p;

int i=0;

int temp;

char str[1024*8+1];

str[1024*8]='\0';

if ((fp=open("TST.DBF",O_RDONLY))==1)

return;

lseek(fp,234*1024*8,SEEK_SET);  //234 是我要打印得数据块

read(fp,str,sizeof(char)*1024*8);

p=(unsigned char *)str;

while(i!=1024*8)

{

temp=(*(p+i)&0xf0)>>4;

cout<

temp=*(p+i)&0x0f;

cout<

i++;

}

close(fp);

}

当然可以使用printf("%x",..) 函数直接打印16进制 ,但上面得代码我自己写了个打印16进制得,功能都一样;

[本帖最后由 fxyj2008 于 2008-1-14 14:21 编辑]

oracle 范鑫_自己写得一个类似AUL的工具,附源代码(C 语言)相关推荐

  1. java实现魔方_闲来无事,用java写了一个魔方小程序。附源码 | 学步园

    闲来无事,用java写了一个魔方小程序.附源码 使用三维数组.相对来说还是简单.呵呵. import java.util.ArrayList; import java.util.List; impor ...

  2. 闲来无事,用java写了一个魔方小程序。附源码

    闲来无事,用java写了一个魔方小程序.附源码 使用三维数组.相对来说还是简单.呵呵. import java.util.ArrayList; import java.util.List; impor ...

  3. python爬虫捕鱼网站_一个简易的爬虫工具,使用Python语言编写,用于zhihu全自动捕鱼...

    简介 这是什么 这是一个简易的爬虫工具,使用Python语言编写,用于zhihu全自动捕鱼,理论上,你可以爬取你感兴趣的任何问题,而不仅仅是小姐姐. 如何使用 编程使用 请确保你的Python版本是3 ...

  4. 写接口给别人调用 推送数据到我们_我们写了一个超好用的抖音矩阵数据管理工具...

    我最近跑了十来个抖音号,遇到一些问题,然后通过我们NB的程序员解决了.如果你也在做抖音矩阵,那这些问题你肯定也会遇到,所以我把解决问题的方法工具化了,给大家用.我遇到的最大的问题,就是账号数据的同步. ...

  5. aspose 转pdf表格大小乱了_自己写了一个小工具类:pdf转word,没有页数和大小限制,保真!...

    昨天下午遇到一个问题,想把一个比较大的pdf转化为word,结果使用了各种工具都收费.想着干脆写一个小工具吧,一开始使用的python等等试了好几个网上的代码,结果全都失真.于是乎不得不花了一下午自己 ...

  6. github用相对路径显示图片_我写了一个开源工具, 让Github的README.md可以正常显示超大图片...

    最终效果对比 图片替换前: 图片显示有好有坏,能否显示,全凭运气 图片替换后: 所有大图正常显示! 本项目永久开源地址 痛点: Github的README.md展示图片效果并不完美 为了让项目演示更生 ...

  7. 毕业时候写的一个PE解析小工具(MFC源码)

    这么快就成了前年毕业的老家伙了.在整理硬盘里的代码和文档的时候翻出刚毕业时候写的一个小东西,想起来那时候在武汉的小河西村,暗无天日的租房里屌丝的写着程序的日子.一晃这么久了.还是混的这鸟样.悲伤逆流成 ...

  8. python打字_使用Python制作一个打字训练小工具

    一.写在前面 说道程序员,你会想到什么呢?有人认为程序员象征着高薪,有人认为程序员都是死肥宅,还有人想到的则是996和 ICU. 别人眼中的程序员:飞快的敲击键盘.酷炫的切换屏幕.各种看不懂的字符代码 ...

  9. 用Python写了一个上课点名系统(附源码)

    今天刷到了一个这样的短视频,我寻思我是不是也可以写一个类似的上课点名程序,想法经不起等待,说写就写~ 一.准备工作 1.Tkinter Tkinter 是 python 内置的 TK GUI 工具集. ...

  10. 搜索python代码的软件_用python编写一个高效搜索代码工具

    用python编写一个高效搜索代码工具 大多码农在linux环境下使用grep+关键词的命令搜索自己想要的代码或者log文件.今天介绍用python如何编写一个更强大的搜索工具,windows下也适用 ...

最新文章

  1. 各种flash的不同
  2. 学python多贵_老男孩学习Python多少钱,学习Python贵吗?
  3. typedef的详细用法
  4. Pycharm-列出代码结构
  5. java全局变量和局部变量_Java 10 –局部变量类型推断
  6. webform窗体怎么实现session唯一标识_微信小程序用户登录和登录态维护的实现_javascript技巧...
  7. 本地安装的smushit,如何压缩图片
  8. android框架连接mysql_三层架构 android访问MSSQL数据库 程序 (服务器端)
  9. Atitit 减少财政支出之减少通讯支出 解决方案attilax总结
  10. 货币基金新规将出,限制T+0提现及支付额度
  11. 凸优化第六章逼近与拟合 6.1范数逼近
  12. java的打印语句_java打印输出语句是什么?
  13. (附源码)计算机毕业设计ssm大学生网络安全题库系统
  14. msdia80.dll文件出现在磁盘根目录下的解决方案
  15. Linux led_class子系统
  16. Win 批处理生成文件目录树
  17. 数字经济下,银行线上场景化建设的服务颗粒度、用户忠诚度和生态融合度
  18. 编程计算: 1!+3!+5!+...+(2n-1)!,要求阶乘计算调用fun函数实现, 数据输入及打印结果在主函数实现。阶乘计算fun函数原型为: long fun(int m); CQUPT题库
  19. VirtualBox - 让分辨率自适应窗口大小
  20. 2进制 16进制 计算机术语,十六进制转二进制计算器

热门文章

  1. Kattis - battleship【模拟】
  2. UML之工具篇(Win10无法使用VGAPlayer播放asf格式与VGA课件的解决办法)
  3. gpu浮点计算能力floaps_认识GPU浮点计算精度
  4. [poj3580]SuperMemo(splay终结题)
  5. ims应用服务器,IMS应用
  6. 深入解析淘宝Diamond之客户端架构
  7. 用于Firefox的Google工具栏Beta 2发布
  8. matlab斯奈尔定律,斯奈尔定律和Zoeppritz方程
  9. 数据分析必备43个Excel函数
  10. sofa接口下载文件