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

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/Chendy/archive/2008/01/10/2033406.aspx

 

  shapefile格式說明及讀寫代碼示例 收藏
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) 1(表示點狀目標) int型 4 1 Little
X方向座標 X方向座標值 double型 8 1 Little
Y方向座標 Y方向座標值 double型 8 1 Little

表2.4點狀目標的記錄內容
下面是讀取點狀目標的記錄內容的代碼:
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) 3(表示線狀目標) 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.2 帶島的多邊形
0
0
5
5
v1
0
v2
 
1
v3
 
2
v4
 
3
v1
 
4
v5
 
5
v8
 
6
v7
 
7
v6
 
8
v5
 
9

 

圖2.3 帶島的多邊形的座標記錄
面狀目標的記錄內容如表2.6:
記錄項 數值 數據類型 長度 個數 位序
幾何類型(ShapeType) 5(表示面狀目標) 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.6面狀目標的記錄內容
下面是讀取面狀目標的記錄內容的代碼:
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文件,也是由頭文件和實體信息兩部分構成(如圖2.4所示)。
文件頭
記錄1  
記錄2  
記錄3  
記錄4  

……
……
記錄n

圖2.4 屬性文件的結構
屬性文件的文件頭
其中文件頭部分的長度是不定長的,它主要對DBF文件作了一些總體說明(見表2.7),其中最主要的是對這個DBF文件的記錄項的信息進行了詳細地描述,比如對每個記錄項的名稱、數據類型、長度等信息都有具體的說明。
在文件中的位置 內容 說明
0 1個字節 表示當前的版本信息
1-3 3個字節 表示最近的更新日期,按照YYMMDD格式。
4-7 1個32位數 文件中的記錄條數。
8-9 1個16位數 文件頭中的字節數。
10-11 1個16位數 一條記錄中的字節長度。
12-13 2個字節 保留字節,用於以後添加新的說明性信息時使用,這裏用0來填寫。
14 1個字節 表示未完成的操作。
15 1個字節 dBASE IV編密碼標記。
16-27 12個字節 保留字節,用於多用戶處理時使用。
28 1個字節 DBF文件的MDX標識。在創建一個DBF 表時,如果使用了MDX 格式的索引文件,那麼 DBF 表的表頭中的這個字節就自動被設置了一個標誌,當你下次試圖重新打開這個DBF表的時候,數據引擎會自動識別這個標誌,如果此標誌爲真,則數據引擎將試圖打開相應的MDX 文件。
29 1個字節 Language driver ID.
30-31 2個字節 保留字節,用於以後添加新的說明性信息時使用,這裏用0來填寫。
32-X (n*32)個字節 記錄項信息描述數組。n表示記錄項的個數。這個數組的結構在表2.8中有詳細的解釋。
X+1 1個字節 作爲記錄項終止標識。

表2.7屬性文件(.dbf)的文件頭
位置 內容 說明
0-10 11個字節 記錄項名稱,是ASCII碼值。
11 1個字節 記錄項的數據類型,是ASCII碼值。(B、C、D、G、L、M和N,具體的解釋見表2.9)。
12-15 4個字節 保留字節,用於以後添加新的說明性信息時使用,這裏用0來填寫。
16 1個字節 記錄項長度,二進制型。
17 1個字節 記錄項的精度,二進制型。
18-19 2個字節 保留字節,用於以後添加新的說明性信息時使用,這裏用0來填寫。
20 1個字節 工作區ID。
21-30 10個字節 保留字節,用於以後添加新的說明性信息時使用,這裏用0來填寫。
31 1個字節 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) 各種字符。

表2.9dbf文件中的數據類型
屬性文件的實體信息
實體信息部分就是一條條屬性記錄,每條記錄都是由若干個記錄項構成,因此只要依次循環讀取每條記錄就可以了。
一個讀取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型,見表2.11。
文件頭
記錄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文件的能力。

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/Chendy/archive/2008/01/10/2033406.aspx

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