shapefile格式說明及讀寫代碼示例(C++)(轉)

hapefile格式說明及讀寫代碼示例

Shape files 數據說明

Shape files  ESRI 提供的一種矢量數據格式,它沒有拓撲信息,一個 Shape files 由一組文件組成,其中必要的基本文件包括座標文件( .shp )、索引文件( .shx )和屬性文件( .dbf )三個文件。

座標文件的結構說明

座標文件 (.shp) 用於記錄空間座標信息。它由頭文件和實體信息兩部分構成(如圖 2.1 所示)。

標文件的文件頭

座標文件的文件頭是一個長度固定 (100 bytes) 的記錄段,一共有 9  int 型和 7  double 型數據,主要記錄內容見表 2.2 

 

文件頭

記錄頭

記錄內容

記錄頭

記錄內容

記錄頭

記錄內容

記錄頭

記錄內容

 

 

 2.1 座標文件的結構

 

起始位置

名稱

數值

類型

位序

0

File Code

9994

Integer

big

4

Unused

0

Integer

big

8

Unused

0

Integer

big

12

Unused

0

Integer

big

16

Unused

0

Integer

big

20

Unused

0

Integer

big

24

文件長度

文件的實際長度

Integer

big

28

版本號

1000

Integer

Little

32

幾何類型

表示這個 Shapefile 文件所記錄的空間數據的幾何類型

Integer

Little

36

Xmin

空間數據所佔空間範圍的 X 方向最小值

Double

Little

44

Ymin

空間數據所佔空間範圍的 Y 方向最小值

Double

Little

52

Xmax

空間數據所佔空間範圍的 X 方向最大值

Double

Little

60

Ymax

空間數據所佔空間範圍的 Y 方向最大值

Double

Little

68*

Zmin

空間數據所佔空間範圍的 Z 方向最小值

Double

Little

76*

Zmax

空間數據所佔空間範圍的 Z 方向最大值

Double

Little

84*

Mmin

最小 Measure 

Double

Little

92*

Mmax

最大 Measure 

Double

Little

 

 2.2shapefiles 頭文件表

注:最後 4 個加星號特別標示的四個數據只有當這個 Shapefile 文件包含 Z 方向 座標或者具有 Measure 值時纔有值,否則爲 0.0 。所謂 Measure 值,是用於存儲需要的 附加數據,可以用來記錄各種數據,例如權值、道路長度等信息。

位序

細心的讀者會注意到表 2.2 中的數值的位序有 Little  big 的區別,對於位序是 big 的數據我們在讀取時要小心。通常,數據的位序都是 Little ,但在有些情況下可能會是 big ,二者的區別在於它們位序的順序相反。一個位序爲 big 的數據,如果我們想得到它的真實數值,需要將它的位序轉換成 Little 即可。轉換原理非常簡單,就是交換字節順序,下面是作者實現的在兩者間進行轉換的程序,代碼如下:

// 位序轉換程序

unsigned long OnChangeByteOrder (int indata)

{

       char ss[8];

       char ee[8];

       unsigned long val = unsigned long(indata);

       _ultoa( val, ss, 16 );// 將十六進制的數 (val) 轉到一個字符串 (ss) 

       int i;

       int length=strlen(ss);

       if(length!=8)

       {

              for(i=0;i<8-length;i++)

                     ee[i]='0';

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

                     ee[i+8-length]=ss[i];

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

                     ss[i]=ee[i];

   }

       ////****** 進行倒序

       int t;

       t      =ss[0];

       ss[0]       =ss[6];

       ss[6]       =t;

       t      =ss[1];

       ss[1]       =ss[7];

       ss[7]       =t;

       t      =ss[2];

       ss[2]       =ss[4];

       ss[4]       =t;

       t      =ss[3];

       ss[3]       =ss[5];

       ss[5]       =t;

    ////******

       //****** 將存有十六進制數 (val) 的字符串 (ss) 中的十六進制數轉成十進制數

       int value=0;

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

       {

              int k;

              CString mass;

              mass=ss[i];

              if(ss[i]=='a' ||

                 ss[i]=='b' ||

                 ss[i]=='c' ||

                 ss[i]=='d' ||

                 ss[i]=='e' ||

                 ss[i]=='f')

                     k=10+ss[i]-'a';

              else

                     sscanf(mass,"%d",&k);

              value=value+int(k*pow(16,7-i));

       }

       return (value);

}

 

Shapefile 文件支持的幾何類型( ShapeType 

Shapefile 文件所支持的幾何類型如表 2.3 所示:

 

編號

幾何類型

0

Null Shape (表示這個 Shapefile 文件不含座標)

1

Point (表示 Shapefile 文件記錄的是點狀目標,但不是多點)

3

PolyLine (表示 Shapefile 文件記錄的是線狀目標)

5

Polygon (表示 Shapefile 文件記錄的是面狀目標)

8

MultiPoint (表示 Shapefile 文件記錄的是多點,即點集合)

11

PointZ (表示 Shapefile 文件記錄的是三維點狀目標)

13

PolyLineZ (表示 Shapefile 文件記錄的是三維線狀目標)

15

PolygonZ (表示 Shapefile 文件記錄的是三維面狀目標)

18

MultiPointZ (表示 Shapefile 文件記錄的是三維點集合目標)

21

PointM (表示含有 Measure 值的點狀目標)

23

PolyLineM (表示含有 Measure 值的線狀目標)

25

PolygonM (表示含有 Measure 值的面狀目標)

28

MultiPointM (表示含有 Measure 值的多點目標)

31

MultiPatch (表示複合目標)

 

 2.3shapefiles 文件支持的幾何類型

對於一個不是記錄 Null Shape 類型的 Shapefile 文件,它所記錄的空間目標的幾何類型必須一致,不能在一個 Shapefile 文件中同時記錄兩種不同類型的幾何目標。

讀取座標文件( .shp )的文件頭的代碼 如下:

void OnReadShp  CString ShpFileName 

{

       FILE*   m_ShpFile_fp;       //****Shp 文件指針

// 打開座標文件

       if((m_ShpFile_fp=fopen(ShpFileName,"rb"))==NULL)

       {

              return;

       }

       // 讀取座標文件頭的內容開始

       int FileCode;

       int Unused;

       int FileLength;

       int Version;

       int ShapeType;

       double Xmin;

       double Ymin;

       double Xmax;

       double Ymax;

       double Zmin;

       double Zmax;

       double Mmin;

       double Mmax;

       fread(&FileCode,     sizeof(int),   1,m_ShpFile_fp);

       FileCode = OnChangeByteOrder(FileCode);

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

              fread(&Unused,sizeof(int),   1,m_ShpFile_fp);

      fread(&FileLength,   sizeof(int),   1,m_ShpFile_fp);

      FileLength      = OnChangeByteOrder(FileLength);

       fread(&Version,          sizeof(int),   1,m_ShpFile_fp);

       fread(&ShapeType,    sizeof(int),   1,m_ShpFile_fp);

       fread(&Xmin,         sizeof(double),1,m_ShpFile_fp);

       fread(&Ymin,         sizeof(double),1,m_ShpFile_fp);

       fread(&Xmax,         sizeof(double),1,m_ShpFile_fp);

       fread(&Ymax,         sizeof(double),1,m_ShpFile_fp);

       fread(&Zmin,         sizeof(double),1,m_ShpFile_fp);

       fread(&Zmax,        sizeof(double),1,m_ShpFile_fp);

       fread(&Mmin,         sizeof(double),1,m_ShpFile_fp);

       fread(&Mmax,         sizeof(double),1,m_ShpFile_fp);

       // 讀取座標文件頭的內容結束

       // 根據幾何類型讀取實體信息

}

實體信息的內容

實體信息負責記錄座標信息,它以記錄段爲基本單位,每一個記錄段記錄一個地理實體目標的座標信息,每個記錄段分爲記錄頭和記錄內容兩部分。

記錄頭的內容包括記錄號( Record Number )和座標記錄長度 (Content Length) 兩個記錄項。它們的位序都是 big 。記錄號( Record Number )和座標記錄長度 (Content Length) 兩個記錄項都是 int 型,並且 shapefile 文件中的記錄號都是從 1 開始的。

記錄內容包括目標的幾何類型( ShapeType )和具體的座標記錄 (X  Y) ,記錄內容因要素幾何類型的不同其具體的內容及格式都有所不同。下面分別介紹點狀目標( Point )、線狀目標( PolyLine )和麪狀目標( Polygon )三種幾何類型的 .shp 文件的記錄內容:

點狀目標

shapefile 中的點狀目標由一對 X  Y 座標構成,座標值爲雙精度型( double )。點狀目標的記錄內容如表 2.4 

 

記錄項

數值

數據類型

長度

個數

位序

幾何類型( ShapeType

(表示點狀目標)

int 

4

1

Little

方向座標

方向座標值

double 

8

1

Little

方向座標

方向座標值

double 

8

1

Little

 

下面是 讀取點狀目標的記錄內容的代碼

OnReadPointShp(CString ShpFileName)

{

       // 打開座標文件

       ……

       // 讀取座標文件頭的內容開始

       ……

       // 讀取點狀目標的實體信息

       int RecordNumber;

       int ContentLength;

       int num   =0;

       while((fread(&RecordNumber,    sizeof(int),   1,ShpFile_fp)!=0))

       {

            num++;

              fread(&ContentLength,sizeof(int),   1,ShpFile_fp);

              RecordNumber      = OnChangeByteOrder(RecordNumber);

              ContentLength       = OnChangeByteOrder(ContentLength);

              int shapeType;

              double x;

double y;

              fread(&shapeType, sizeof(int),   1,ShpFile_fp);

              fread(&x, sizeof(double),   1,ShpFile_fp);

              fread(&y, sizeof(double),   1,ShpFile_fp);

}

}

線狀目標

shapefile 中的線狀目標是由一系列點座標串構成,一個線目標可能包括多個子線段,子線段之間可以是相離的,同時子線段之間也可以相交。 Shapefile 允許出現多個座標完全相同的連續點,當讀取文件時一定要注意這種情況,但是不允許出現某個退化的、長度爲 0 的子線段出現。線狀目標的記錄內容如表 2.5 

 

記錄項

數值

數據類型

長度

個數

位序

幾何類型( ShapeType 

(表示線狀目標)

int 

4

1

Little

座標範圍( Box 

表示當前線目標的座標範圍

double 

32

4

Little

子線段個數( NumParts 

表示構成當前線目標的子線段的個數

int 

4

1

Little

座標點數( NumPoints 

表示構成當前線目標所包含的座標點個數

int 

4

1

Little

Parts 數組

記錄了每個子線段的座標在 Points 數組中的起始位置

int 

4×NumParts

NumParts

Little

Points 數組

記錄了所有的座標信息

Point 

根據點個數來確定

NumPoints

Little

 

 2.5 線狀目標的記錄內容

具體的數據結構如下:

PolyLine

{

Double[4]               Box               // 當前線狀目標的座標範圍

Integer                   NumParts     // 當前線目標所包含的子線段的個數

Integer                   NumPoints   // 當前線目標所包含的頂點個數

Integer[NumParts]  Parts              // 每個子線段的第一個座標點在 Points 的位置

Point[NumPoints]    Points             // 記錄所有座標點的數組

}

這些記錄項的具體含義如下:

Box 記錄了當前的線目標的座標範圍,它是一個 double 型的數組,按照 Xmin  Ymin  Xmax  Ymax 的順序記錄了座標範圍;

NumParts 記錄了當前線目標所包含的子線段的個數;

NumPoints 記錄了當前線目標的座標點總數;

Parts 記錄了每個子線段的第一個座標點在座標數組 points 中的位置,以便讀取數據;

Points 是用於存放當前線目標的 X  Y 座標的數組。

下面是讀取線狀目標的記錄內容的代碼:

OnReadLineShp(CString ShpFileName)

{

       // 打開座標文件

       ……

       // 讀取座標文件頭的內容開始

       ……

       // 讀取線狀目標的實體信息

       int RecordNumber;

       int ContentLength;

       int num   =0;

       while((fread(&RecordNumber,    sizeof(int),   1,ShpFile_fp)!=0))

{

              fread(&ContentLength,sizeof(int),   1,ShpFile_fp);

              RecordNumber      = OnChangeByteOrder (RecordNumber);

              ContentLength       = OnChangeByteOrder (ContentLength);

              int shapeType;

              double Box[4];

              int NumParts;

              int NumPoints;

              int *Parts;

              fread(&shapeType,    sizeof(int),   1,ShpFile_fp);   //  Box

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

                     fread(Box+i,     sizeof(double),1,ShpFile_fp);   //  NumParts  NumPoints

              fread(&NumParts,     sizeof(int),   1,ShpFile_fp);

              fread(&NumPoints,    sizeof(int),   1,ShpFile_fp);   //  Parts  Points

              Parts   = new int[NumParts];

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

fread(Parts+i,   sizeof(int),   1,ShpFile_fp);

              int pointNum;

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

              {

                     if(i!=NumParts-1)

                            pointNum       =Parts[i+1]-Parts[i];

                     else

                            pointNum       =NumPoints-Parts[i];

                     double *PointsX;

                     double *PointsY;

                    

                     PointsX =new double[pointNum];

                     PointsY =new double[pointNum];

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

                     {

                            fread(PointsX+j, sizeof(double),1,ShpFile_fp);

                            fread(PointsY+j, sizeof(double),1,ShpFile_fp);

                     }

                     delete[] PointsX;

                     delete[] PointsY;

              }

              delete[] Parts;

       }

}

面狀目標

shapefile 中的面狀目標是由多個子環構成,每個子環是由至少四個頂點構成的封閉的、無自相交現象的環。對於含有島的多邊形,構成它的環有內外環之分,每個環的頂點的排列順序或者方向說明了這個環到底是內環還是外環。一個內環的頂點是按照逆時針順序排列的;而對於外環,它的頂點排列順序是順時針方向。如果一個多邊形只由一個環構成,那麼它的頂點排列順序肯定是順時針方向。

每條多邊形記錄的數據結構與線目標的數據結構完全相同,

Polygon

{

Double[4]               Box               // 當前面狀目標的座標範圍

Integer                   NumParts     // 當前面目標所包含的子環的個數

Integer                   NumPoints   // 構成當前面狀目標的所有頂點的個數

Integer[NumParts]  Parts              // 每個子環的第一個座標點在 Points 的位置

Point[NumPoints]    Points             // 記錄所有座標點的數組

}

對於一個 shapefile 中的多邊形,它必須滿足下面三個條件:

構成多邊形的每個子環都必須是閉合的,即每個子環的第一個頂點跟最後一個頂點是同一個點;

每個子環在 Points 數組中的排列順序並不重要,但每個子環的頂點必須按照一定的順序連續排列;

存儲在 shapefile 中的多邊形必須是乾淨的。所謂一個乾淨的多邊形,它必須滿足兩點:

沒有自相交現象。這就要求任何一個子環不能跟其它的子環相交,共線的現  象也將被當作相交。但是允許兩個子環的頂點重合;

對於一個不含島的多邊形或者是含島的多邊形的外環,它們的頂點排列順序必須是順時針方向;而對於內環,它的排列順序必須是逆時針方向。所謂的 “ 髒多邊形 ” 就是指頂點排列順序爲順時針的內環。

 2.2 中的多邊形是一個典型的例子。這個多邊形包括一個島,所有頂點的個數爲 8  NumParts 等於 2  NumPoints 等於 10 。請注意內環(島)的頂點的排列順序是逆時針的(如圖 2.3 所示)

 2.6 :面狀目標的記錄內容

 

記錄項

數值

數據類型

長度

個數

位序

幾何類型( ShapeType 

(表示面狀目標)

int 

4

1

Little

座標範圍( Box 

表示當前面目標的座標範圍

double 

32

4

Little

子線段個數( NumParts 

表示構成當前面狀目標的子環的個數

int 

4

1

Little

座標點數( NumPoints 

表示構成當前面狀目標所包含的座標點個數

int 

4

1

Little

Parts 數組

記錄了每個子環的座標在 Points 數組中的起始位置

int 

4×NumParts

NumParts

Little

Points 數組

記錄了所有的座標信息

Point 

根據點個數來確定

NumPoints

Little

 

下面是 讀取面狀目標的記錄內容的代碼

void OnReadAreaShp(CString ShpFileName)

{

       // 打開座標文件

       ……

       // 讀取座標文件頭的內容開始

       ……

       // 讀取面狀目標的實體信息

       int RecordNumber;

       int ContentLength;

       while((fread(&RecordNumber,    sizeof(int),   1,m_ShpFile_fp)!=0))

       {

              fread(&ContentLength,sizeof(int),   1,m_ShpFile_fp);

              RecordNumber      = OnChangeByteOrder (RecordNumber);

              ContentLength       = OnChangeByteOrder (ContentLength);

              int shapeType;

              double Box[4];

              int NumParts;

              int NumPoints;

              int *Parts;

              fread(&shapeType,    sizeof(int),   1,m_ShpFile_fp);

              //  Box

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

           fread(Box+i,     sizeof(double),1,m_ShpFile_fp);

              //  NumParts  NumPoints

              fread(&NumParts,     sizeof(int),   1,m_ShpFile_fp);

              fread(&NumPoints,    sizeof(int),   1,m_ShpFile_fp);

              //  Parts  Points

              Parts       =new int[NumParts];

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

                     fread(Parts+i,   sizeof(int),   1,m_ShpFile_fp);

              int pointNum;

              int xx;

              int yy;

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

              {

                     if(i!=NumParts-1)

                            pointNum       =Parts[i+1]-Parts[i];

            else

                            pointNum       =NumPoints-Parts[i];

                    

                     double *PointsX;

                     double *PointsY;

                    

                     PointsX =new double[pointNum];

                     PointsY =new double[pointNum];

                    

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

                     {

                            fread(PointsX+j, sizeof(double),1,m_ShpFile_fp);

                            fread(PointsY+j, sizeof(double),1,m_ShpFile_fp);

                     }

                     delete[] PointsX;

                     delete[] PointsY;

              }

              delete[] Parts;

       }

}

屬性文件的結構說明

屬性文件 (.dbf) 用於記錄屬性信息。它是一個標準的 DBF 文件,也是由頭文件和實體信息兩部分構成。

 

文件頭

記錄 1

 

記錄 2

 

記錄 3

 

記錄 4

 

 

……

 

記錄 n

 

屬性文件的文件頭

其中文件頭部分的長度是不定長的,它主要對 DBF 文件作了一些總體說明(見表 2.7 ),其中最主要的是對這個 DBF 文件的記錄項的信息進行了詳細地描述,比如對每個記錄項的名稱、數據類型、長度等信息都有具體的說明。

 

在文件中的位置

內容

說明

0

個字節

表示當前的版本信息

 3

個字節

表示最近的更新日期,按照 YYMMDD 格式。

 7

 32 位數

文件中的記錄條數。

 9

 16 位數

文件頭中的字節數。

10  11

 16 位數

一條記錄中的字節長度。

12  13

個字節

保留字節,用於以後添加新的說明性信息時使用,這裏用 0 來填寫。

14

個字節

表示未完成的操作。

15

個字節

dBASE IV 編密碼標記。

16  27

12 個字節

保留字節,用於多用戶處理時使用。

28

個字節

DBF 文件的 MDX 標識。在創建一個 DBF 表時,如果使用了 MDX 格式的索引文件,那麼 DBF 表的表頭中的這個字節就自動被設置了一個標誌,當你下次試圖重新打開這個 DBF 表的時候,數據引擎會自動識別這個標誌,如果此標誌爲真,則數據引擎將試圖打開相應的 MDX 文件。

29

個字節

Language driver ID.

30  31

個字節

保留字節,用於以後添加新的說明性信息時使用,這裏用 0 來填寫。

32  X

 n*32 )個字節

記錄項信息描述數組。 n 表示記錄項的個數。這個數組的結構在表 2.8 中有詳細的解釋。

 1

個字節

作爲記錄項終止標識。

 

 2.7 屬性文件( .dbf )的文件頭

 

位置

內容

說明

 10

11 個字節

記錄項名稱,是 ASCII 碼值。

11

個字節

記錄項的數據類型,是 ASCII 碼值。( B  C  D  G  L  M ,具體的解釋見表 2.9 )。

12  15

個字節

保留字節,用於以後添加新的說明性信息時使用,這裏用 0 來填寫。

16

個字節

記錄項長度,二進制型。

17

個字節

記錄項的精度,二進制型。

18  19

個字節

保留字節,用於以後添加新的說明性信息時使用,這裏用 0 來填寫。

20

個字節

工作區 ID 

21  30

10 個字節

保留字節,用於以後添加新的說明性信息時使用,這裏用 0 來填寫。

31

個字節

MDX 標識。如果存在一個 MDX 格式的索引文件,那麼這個記錄項爲真,否則爲空。

 

 2.8 記錄項信息描述

 

代碼

數據類型

允許輸入的數據

B

二進制型

各種字符。

C

字符型

各種字符。

D

日期型

用於區分年、月、日的數字和一個字符,內部存儲按照 YYYYMMDD 格式。

G

(General

or OLE)

各種字符。

N

數值型 (Numeric)

- . 0 1 2 3 4 5 6 7 8 9

L

邏輯型( Logical

? Y y N n T t F f (? 表示沒有初始化 ) 

M

(Memo)

各種字符。

 

屬性文件的實體信息

實體信息部分就是一條條屬性記錄,每條記錄都是由若干個記錄項構成,因此只要依次循環讀取每條記錄就可以了。

一個讀取 dbf 文件的例子

假設要讀取一個名爲 soil  dbf 文件(存儲了土地利用信息),它含有 8 個記錄項,記錄項信息如表 2.10 所示:

 

記錄項名稱

數據類型

長度

小數位數

Area

數值型( double 

31

15

Perimeter

數值型( double 

31

15

soils_

數值型( int 

11

0

soils_id

數值型( int 

11

0

soil_code

字符型( character 

3

Suit

字符型( character 

1

Centroid_x

數值型( double 

31

15

Centroid_y

數值型( double 

31

15

 

 2.10dbf 文件中的數據類型

下面是讀取這個 dbf 文件的代碼:

void OnReadDbf(CString DbfFileName)

{

       FILE*   m_DbfFile_fp;       //****Dbf 文件指針

       // 打開 dbf 文件

       if((m_DbfFile_fp=fopen(DbfFileName,"rb"))==NULL)

       {

             return;

       }

       int i,j;

       //////**** 讀取 dbf 文件的文件頭  開始

       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);

      

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

       {

              fread(&Unused,        sizeof(int),   1,m_DbfFile_fp);

       }

       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;

       // 讀取記錄項信息-共有 8 個記錄項

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

       {

              //FieldName----11   bytes

              fread(name,    11, 1,m_DbfFile_fp);

              //FieldType----1     bytes

              fread(&fieldType,   sizeof(BYTE), 1,m_DbfFile_fp);

              //Reserved3----4     bytes

              Reserved3      =0;

              fread(&Reserved3, sizeof(int), 1,m_DbfFile_fp);

              //FieldLength--1     bytes

              fread(&fieldLength,sizeof(BYTE), 1,m_DbfFile_fp);

              //DecimalCount-1   bytes

              fread(&decimalCount,sizeof(BYTE), 1,m_DbfFile_fp);

              //Reserved4----2     bytes

              Reserved4      =0;

              fread(&Reserved4, sizeof(short), 1,m_DbfFile_fp);

              //WorkID-------1    bytes

          fread(&workID,            sizeof(BYTE), 1,m_DbfFile_fp);

              //Reserved5----10   bytes

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

              {

                     fread(Reserved5+j,sizeof(short), 1,m_DbfFile_fp);

              }

              //MDXFlag1-----1 bytes

              fread(&mDXFlag1,       sizeof(BYTE), 1,m_DbfFile_fp);

       }

       BYTE terminator;

       fread(&terminator,      

 sizeof(BYTE), 1,m_DbfFile_fp);       // 讀取 dbf 文件頭結束

       double Area,Perimeter,Centroid_y,Centroid_x;

       int Soils_,Soils_id;

       CString Soil_code,suit;

       BYTE   deleteFlag;

       char media[31];

       // 讀取 dbf 文件記錄  開始

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

       {

              fread(&deleteFlag, sizeof(BYTE), 1,m_DbfFile_fp);              // 讀取 Area double

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              Area =atof(media);              // 讀取 Perimeter double

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              Perimeter =atof(media);             // 讀取 soils_ int

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

                     strcpy(media+j,"");

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              Soils_      =atoi(media);              // 讀取 Soils_id int

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

                     strcpy(media+j,"");

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              Soils_id   =atoi(media);

              // 讀取 soil_code string

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

                     strcpy(media+j,"");

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              Soil_code       =media;              // 讀取 suit string

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

                     strcpy(media+j,"");

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              suit =media;              // 讀取 Centroid_y double

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

                     strcpy(media+j,"");

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              Centroid_y      =atof(media);              // 讀取 Centroid_x double

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

                     strcpy(media+j,"");

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

                     fread(media+j, sizeof(char), 1,m_DbfFile_fp);

              Centroid_x      =atof(media);

       }

       // 讀取 dbf 文件記錄  結束

}

索引文件的結構說明

索引文件( .shx )主要包含座標文件的索引信息,文件中每個記錄包含對應的座標文件記錄距離座標文件的文件頭的偏移量。通過索引文件可以很方便地在座標文件中定位到指定目標的座標信息。

索引文件也是由頭文件和實體信息兩部分構成(如圖 2.5 ),其中文件頭部分是一個長度固定 (100 bytes) 的記錄段,其內容與座標文件的文件頭基本一致。它的實體信息以記錄爲基本單位,每一條記錄包括偏移量( offset )和記錄段長度( Content Length )兩個記錄項,它們的位序都是 big ,兩個記錄項都是 int 型。

 

文件頭

記錄 1

 

記錄 2

 

記錄 3

 

記錄 4

 

 

……

……

 

記錄 n

 

 

 

 

 2.5 索引文件的結構

 

記錄項

數值

數據類型

長度

個數

位序

位移量( Offset 

表示座標文件中的對應記錄的起始位置相對於座標文件起始位置的位移量。

int 

4

1

Big

記錄長度

 Content Length 

表示座標文件中的對應記錄的長度。

int 

4

1

Big

 

 2.11 索引文件的記錄內容

下面是一段讀取索引文件的代碼:

void OnReadShx  CString ShxFileName 

{

       FILE*   m_ShxFile_fp;       //****Shx 文件指針

       // 打開索引文件

       if((m_ShxFile_fp=fopen(ShxFileName,"rb"))==NULL)

       {

              return;

       }

       // 讀取索引文件頭的內容開始

       int FileCode;

       int Unused;

       int FileLength;

       int Version;

     int ShapeType;

       double Xmin;

       double Ymin;

       double Xmax;

       double Ymax;

       double Zmin;

       double Zmax;

       double Mmin;

       double Mmax;

       fread(&FileCode,     sizeof(int),   1,m_ShxFile_fp);

       FileCode = OnChangeByteOrder(FileCode);

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

              fread(&Unused,sizeof(int),   1,m_ShxFile_fp);

       fread(&FileLength,   sizeof(int),   1,m_ShxFile_fp);

       FileLength      = OnChangeByteOrder(FileLength);

       fread(&Version,          sizeof(int),   1,m_ShxFile_fp);

       fread(&ShapeType,    sizeof(int),   1,m_ShxFile_fp);

       fread(&Xmin,         sizeof(double),1,m_ShxFile_fp);

       fread(&Ymin,         sizeof(double),1,m_ShxFile_fp);

       fread(&Xmax,         sizeof(double),1,m_ShxFile_fp);

       fread(&Ymax,         sizeof(double),1,m_ShxFile_fp);

      fread(&Zmin,         sizeof(double),1,m_ShxFile_fp);

       fread(&Zmax,        sizeof(double),1,m_ShxFile_fp);

       fread(&Mmin,         sizeof(double),1,m_ShxFile_fp);

       fread(&Mmax,         sizeof(double),1,m_ShxFile_fp);

       // 讀取索引文件頭的內容結束

      

              int Offset, ContentLength;

       // 讀取實體信息

       while((fread(&Offset,    sizeof(int),   1, m_ShxFile_fp)!=0))

       {

              fread(&ContentLength,sizeof(int),   1, m_ShxFile_fp);

              Offset            = OnChangeByteOrder(Offset);

              ContentLength       = OnChangeByteOrder(ContentLength);

       }

}

小結

本節介紹了 MapObjects 支持的各種數據,並詳細介紹了 shapefiles 的文件結構,同時給出了讀取 shapefiles 的座標文件( .shp )、屬性文件( .dbf )和索引文件( .shx )的程序,給出這些程序的目的在於讓讀者通過這些例子深入掌握 shapefiles 文件的格式,進而具備將特定格式的數據文件轉換成 shapefiles 文件的能力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章