1.DBF文件要點
DBF文件又叫屬性文件,也叫dBASE文件,文件后綴是.dbf,實際上ArcGIS打開后的屬性表就是DBF的信息。DBF文件遵循以下幾個條件:
- 每個要素在表中必須要包含一個與之相對應的記錄。
- 記錄的順序必須與要素在主文件中(*.shp)的順序一樣。
- dBASE 文件頭中的年份值必須要晚於 1900 年。
2.DBF文件的組成
屬性文件(.dbf)用於記錄屬性信息。它是一個標准的DBF文件,也是由頭文件和實體信息兩部分構成:
3.DBF文件的頭文件
文件頭部分的長度是不定長的,它主要對DBF文件作了一些總體說明。
其中最主要的是對這個DBF文件的記錄項(字段)的信息進行了詳細地描述,比如對每個記錄項(字段)的名稱、數據類型、長度等信息都有具體的說明。
3.1頭文件
- date[3],BYTE,更新日期
- verision,BYTE類型,版本信息
- RecordNum,int,文件中記錄條數
- HeaderByteNum,short,文件頭的字節數
- RecordByteNum,short,一條記錄的字節長度
- Reserved1,short
- Flag4s,BYTE
- EncrypteFlag,BYTE
- Unused[3],int,保留字節
- MDXFlag,BYTE,MDX標識
- LDriID,BYTE
- Reserved2,short
- RecordItem(記錄項數組詳情見下),32,字段描述信息
- terminator,BYTE,終止標識
- 頭文件的字節數為:1 + 1 * 3 + 4 + 2 + 2 + 2 + 1 + 1 + 4 * 3 + 1 + 1 + 2 + 32 * RecordNum + 1 = 33 + 32 * RecordNum
3.2記錄項數組
記錄項數組其實就是描述表中字段信息的數組
- name[11],BYTE,字段名
- fieldType,BYTE,字段類型,包括B、C、D、G、L、M和N
- Reserved3,int
- fieldLength,BYTE,記錄項長度
- decimalCount,BYTE,記錄項精度
- Reserved4,short
- workID,BYTE
- Reserved5[5],short,
- mDXFflag1,BYTE
- 一個記錄項字節數為:11 + 1 + 4 + 1 + 1 + 2 + 1 + 5 * 2 + 1 = 32
記錄項描述信息中fieldType的類型說明
4.實體信息
實體信息部分就是一條條屬性記錄,每條記錄都是由若干個記錄項(字段)構成,因此只要依次循環讀取每條記錄就可以了。
5.讀取DBF代碼
由於實際上每個shp文件的表的字段數可能不一樣,並且每個字段的類型不固定,需要每次判定字段類型,然后根據不同類型設置來讀取信息。可以根據字段數量設置一個數組,數組的每個元素存儲對應順序字段的類型,然后根據數組元素的值定義變量獲取記錄的信息。
上述想法是一種比較完善的做法,即對於任何數量和類型的字段都可以滿足要求,也應該是ArcGIS讀取表的方法。完善即代表需要考慮各種情況,費時費力。
這里根據實際情況,簡化一下,讀取已知字段數和字段類型的DBF的信息。
假設要讀取一個八個字段的表:
- int類型:ObjectID,Ecrm,Elevt
- double類型:shapeArea,shapeLength
- CString類型:Dest,Ec,cc
代碼如下
void readDbf(CString filename) { //****在讀取shp之后打開DBF文件 int n = filename.ReverseFind('.'); filename = filename.Left(n); filename = filename + ".dbf"; FILE* m_DbfFile_fp;//****Dbf文件指針 if ((m_DbfFile_fp = fopen(filename, "rb")) == NULL)//打開dbf文件 return; //****讀取dbf文件的文件頭 int i, j; BYTE version; fread(&version, 1, 1, m_DbfFile_fp); BYTE date[3]; for (i = 0; i<3; i++) fread(date + i, 1, 1, m_DbfFile_fp); int RecordNum;//文件中的記錄條數 fread(&RecordNum, sizeof(int), 1, m_DbfFile_fp); short HeaderByteNum;//文件頭中的字節數 fread(&HeaderByteNum, sizeof(short), 1, m_DbfFile_fp); short RecordByteNum;//一條記錄中的字節長度 fread(&RecordByteNum, sizeof(short), 1, m_DbfFile_fp); short Reserved1; fread(&Reserved1, sizeof(short), 1, m_DbfFile_fp); BYTE Flag4s; fread(&Flag4s, sizeof(BYTE), 1, m_DbfFile_fp); BYTE EncrypteFlag; fread(&EncrypteFlag, sizeof(BYTE), 1, m_DbfFile_fp); int Unused[3]; for (i = 0; i<3; i++) fread(Unused + i, sizeof(int), 1, m_DbfFile_fp); int a = Unused[0]; int b = Unused[1]; int c = Unused[2]; BYTE MDXFlag; fread(&MDXFlag, sizeof(BYTE), 1, m_DbfFile_fp); BYTE LDriID; fread(&LDriID, sizeof(BYTE), 1, m_DbfFile_fp); short Reserved2; fread(&Reserved2, sizeof(short), 1, m_DbfFile_fp); BYTE name[11]; BYTE fieldType; int Reserved3; BYTE fieldLength; BYTE decimalCount; short Reserved4; BYTE workID; short Reserved5[5]; BYTE mDXFlag1; int fieldscount; fieldscount = (HeaderByteNum - 32) / 32; fieldscount_final = fieldscount; //****讀取記錄項信息-共有8個記錄項 for (i = 0; i< fieldscount; i++)//字段數 { RecordItem recordItem; //定義記錄項存儲信息,便於寫dbf使用 fread(name, 11, 1, m_DbfFile_fp); //FieldName----11 bytes memcpy(recordItem.name, name, 11); fread(&fieldType, sizeof(BYTE), 1, m_DbfFile_fp); //FieldType----1 bytes recordItem.fieldType = fieldType; fread(&Reserved3, sizeof(int), 1, m_DbfFile_fp); //Reserved3----4 bytes recordItem.Reserved3 = Reserved3; fread(&fieldLength, sizeof(BYTE), 1, m_DbfFile_fp); //FieldLength--1 bytes recordItem.fieldLength = fieldLength; fread(&decimalCount, sizeof(BYTE), 1, m_DbfFile_fp);//DecimalCount-1 bytes recordItem.decimalCount = decimalCount; fread(&Reserved4, sizeof(short), 1, m_DbfFile_fp); //Reserved4----2 bytes recordItem.Reserved4 = Reserved4; fread(&workID, sizeof(BYTE), 1, m_DbfFile_fp); //WorkID-------1 bytes recordItem.workID = workID; for (j = 0; j<5; j++) //Reserved5----10 bytes fread(Reserved5 + j, sizeof(short), 1, m_DbfFile_fp); memcpy(recordItem.Reserved5, Reserved5, 10); fread(&mDXFlag1, sizeof(BYTE), 1, m_DbfFile_fp); //MDXFlag1-----1 bytes recordItem.mDXFlag1 = mDXFlag1; recordItems.push_back(recordItem); } BYTE terminator; //terminator----1 bytes fread(&terminator, sizeof(BYTE), 1, m_DbfFile_fp); //****讀取dbf文件頭結束 //****讀取dbf文件記錄 開始 int ObjectID, Ecrm, Elevt; double shapeArea, shapeLength; CString Dest, Ec, cc; BYTE deleteFlag; char media[40]; vector<CString> polygonAttribute; vector<double> ShapeArea; vector<int>temp1; for (i = 0; i<RecordNum; i++) { fread(&deleteFlag, sizeof(BYTE), 1, m_DbfFile_fp); //讀取刪除標記 1字節 //****讀取 ObjectID int for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<10; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--10 ObjectID = atoi(media); //****讀取 Dest string for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<32; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--32 Dest = media; //****讀取 Ec string for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<16; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--16 Ec = media;//同上 //****讀取 EcRm int for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<10; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--10 Ecrm = atoi(media); //****讀取 Elevt int for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<10; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--10 Elevt = atoi(media); //****讀取 Cc int for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<8; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--8 cc = media;//4值4'' //****讀取 shape_length double for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<19; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--19 shapeLength = atof(media);//帶e的 //****讀取 shape_Area double for (j = 0; j<40; j++) strcpy(media + j, "\0"); for (j = 0; j<19; j++) fread(media + j, sizeof(char), 1, m_DbfFile_fp); //--19 shapeArea = atof(media); } //****讀取dbf文件記錄 結束 }
這是在已知字段數和字段類型情況下讀取的情況,如果未知的情況下,需要設置數組存儲每個字段的類型,則數組的長度就是字段數量;在讀取實體記錄時,根據數組的每個元素的值設定對應類型的變量,來存儲記錄信息,必要時最后結果要轉化(如字符型轉化成整型)。這一部分大家可以自己去完善。
下一篇我們將講述shx文件的讀取。