Shape files數據說明
Shape files是ESRI提供的一種矢量數據格式,它沒有拓撲信息,一個Shape files由一組文件組成,其中必要的基本文件包括坐標文件(.shp)、索引文件(.shx)和屬性文件(.dbf)三個文件。
1. 坐標文件的結構說明––
坐標文件(.shp)用於記錄空間坐標信息。它由頭文件和實體信息兩部分構成(如圖2.1所示)。
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.2 shapefiles 頭文件表
注:最后4個加星號特別標示的四個數據只有當這個Shapefile文件包含Z方向坐標或者具有Measure值時才有值,否則為0.0。所謂Measure值,是用於存儲需要的附加數據,可以用來記錄各種數據,例如權值、道路長度等信息。
(1) 位序
細心的讀者會注意到表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);
}
(2) Shapefile文件支持的幾何類型(ShapeType)
Shapefile文件所支持的幾何類型[微軟用戶1] 如表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.3 shapefiles文件支持的幾何類型
對於一個不是記錄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);
//讀取坐標文件頭的內容 結束
//根據幾何類型讀取實體信息
……
}
2) 實體信息的內容
實體信息負責記錄坐標信息,它以記錄段為基本單位,每一個記錄段記錄一個地理實體目標的坐標信息,每個記錄段分為記錄頭和記錄內容兩部分。
記錄頭的內容包括記錄號(Record Number)和坐標記錄長度(Content Length) 兩個記錄項。它們的位序都是big。記錄號(Record Number)和坐標記錄長度(Content Length) 兩個記錄項都是int型,並且shapefile文件中的記錄號都是從1開始的。
記錄內容包括目標的幾何類型(ShapeType)和具體的坐標記錄(X、Y) ,記錄內容因要素幾何類型的不同其具體的內容及格式都有所不同。下面分別介紹點狀目標(Point)、線狀目標(PolyLine)和面狀目標(Polygon)三種幾何類型的.shp文件的記錄內容:
(1) 點狀目標
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);
}
}
(2) 線狀目標
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;
}
}
(3) 面狀目標
shapefile中 的面狀目標是由多個子環構成,每個子環是由至少四個頂點構成的封閉的、無自相交現象的環。對於含有島的多邊形,構成它的環有內外環之分,每個環的頂點的排 列順序或者方向說明了這個環到底是內環還是外環。一個內環的頂點是按照逆時針順序排列的;而對於外環,它的頂點排列順序是順時針方向。如果一個多邊形只由 一個環構成,那么它的頂點排列順序肯定是順時針方向。
每條多邊形記錄的數據結構與線目標的數據結構完全相同,
Polygon
{
Double[4] Box // 當前面狀目標的坐標范圍
Integer NumParts // 當前面目標所包含的子環的個數
Integer NumPoints // 構成當前面狀目標的所有頂點的個數
Integer[NumParts] Parts // 每個子環的第一個坐標點在Points的位置
Point[NumPoints] Points // 記錄所有坐標點的數組
}
對於一個shapefile中的多邊形,它必須滿足下面三個條件:
l 構成多邊形的每個子環都必須是閉合的,即每個子環的第一個頂點跟最后一個頂點是同一個點;
l 每個子環在Points數組中的排列順序並不重要,但每個子環的頂點必須按照一定的順序連續排列;
l 存儲在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;
}
}
2. 屬性文件的結構說明
屬性文件(.dbf)用於記錄屬性信息。它是一個標准的DBF文件,也是由頭文件和實體信息兩部分構成(如圖2.4所示)。
文件頭 |
|
記錄1 |
|
記錄2 |
|
記錄3 |
|
記錄4 |
|
……
……
記錄n |
圖2.4 屬性文件的結構
1) 屬性文件的文件頭
其中文件頭部分的長度是不定長的,它主要對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.9 dbf文件中的數據類型
2) 屬性文件的實體信息
實體信息部分就是一條條屬性記錄,每條記錄都是由若干個記錄項構成,因此只要依次循環讀取每條記錄就可以了。
3) 一個讀取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.10 dbf文件中的數據類型
下面是讀取這個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文件記錄 結束
}
3. 索引文件的結構說明
索引文件(.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);
}
}
2.2.3 小結
本節介紹了MapObjects支持的各種數據,並詳細介紹了shapefiles的文件結構,同時給出了讀取shapefiles的坐標文件(.shp)、屬性文件(.dbf)和索引文件(.shx)的程序,給出這些程序的目的在於讓讀者通過這些例子深入掌握shapefiles文件的格式,進而具備將特定格式的數據文件轉換成shapefiles文件的能力。
[微軟用戶1]ShapeFile支持的幾何類型