張凱旋, 鄒業斌, 劉曇曇, 馬文濤
(中國礦業大學(北京),北京 100083)
地理信息系統是一種采集、存儲、管理、分析、顯示與應用地理信息的計算機系統[1],以數字化的形式反映地球空間現勢和變遷的各種空間數據并描述這些空間數據特征的屬性,以及使用模型化的方法來模擬地球空間對象的行為,在計算機軟、硬件的支持下,以特定的格式支持輸入/輸出、存貯、顯示以及進行地理空間信息查詢、綜合分析、輔助決策,為人們提供處理地理信息最佳的方法和手段[2]。隨著互聯網技術的發展,大數據和云計算等技術的興起,使WebGIS應用得到了飛速的發展。利用Internet在Web上發布和出版地理信息,為用戶提供空間數據的瀏覽、查詢、制作專題圖和分析的功能,從而實現地理信息的共享,已經成為GIS發展的必然趨勢[3]。在實際WebGIS開發中會需要上傳本地的ShapeFile文件并結合WebGIS系統進行分析,Esri的服務非常昂貴,因此在小規模的GIS平臺搭建過程中可搭建本地后臺解析系統。本文詳細介紹了ShapeFile的文件結構,根據ShapeFile文件的結構,利用.NET技術進行解析,并展示到Web前端。對各學者建設WebGIS平臺有所借鑒。
一個完整的ESRI的ShapeFile文件包括一個主文件*.shp,一個索引文件*.shx,和一個屬性文件*.dbf。主文件是一個直接存取,記錄長度文件,其中每個記錄描述一個由其頂點列表組成的ShapeFile。在索引文件中,每條記錄是在主文件中記錄對應距離主文件頭部的偏移量。*.dbf中記錄的是對應主文件中記錄的屬性記錄,每條主文件記錄對應*.dbf中的一條屬性記錄。*.prj文件用于存儲坐標系的信息;*.xml文件作為元數據文件,用于存儲ShapeFile的相關信息[4]。
主文件用來存儲地理要素的幾何圖形,一個.shp文件由文件頭和記錄實體兩部分組成[5]。主文件頭100字節長。表1描述了文件頭中數據的字節位置、值類型和字節順序。在表1中,位置是相對于文件頭的。文件頭的布局如表1所示。

表1 主文件頭結構表Table 1 Structure table of main file header
.shx索引文件是存儲圖形要素與屬性信息索引的文件,主要起到定位的作用,其由文件頭和記錄兩部分組成,文件頭的內容與主文件的基本一致[5]。每條記錄由8個字節組成,具體內容如表2所示。其中,Offset可以理解為該條記錄在.shp文件中的偏移量,Content Length可以理解為該記錄的長度。

表2 索引文件記錄結構表Table 2 Structure table of index file record
.dbf屬性表文件,是由頭記錄及數據記錄組成。頭記錄定義了該表的結構并包含與表相關的其它信息,它主要對屬性文件作一些概括性描述,尤其是對屬性文件的記錄項信息進行著重性說明,比如對每個記錄項的名稱、數據類型、精度、長度都作了詳細地介紹。
本地文件利用Ajax技術通過Post提交方式異步上傳給后臺服務端,后臺服務端通過HttpPostedFile接受前端傳遞過來的文件并且通過FileStream類讀取文件上傳到文件服務器[6]。然后調用WebService服務利用BinaryReader類以二進制文件流的方式對ShapeFile進行解析,以集合的方式返回解析后的數據。將集合數據轉換成JSON數據格式,利用ArcGIS for JavaScript庫類展示數據,流程如圖1。

圖1 解析流程圖Fig.1 Analytical flow chart
HttpPostedFile postedFile =context.Request.Files[0]; //接收文件
postedFile.SaveAs(context.Request.MapPath(fullDir)); //保存文件
FileStream fo= new System.IO.FileStream
(context.Request.MapPath(shxpath),FileMode.Open,FileAccess.Read);
//文件流形式
以文件流的方式將前端Web Browser上傳的文件存儲到文件服務器,利用FileStream分別讀取.shp、.shx和.dbf文件,FileStream讀寫操作可以指定為同步或異步操作。同時支持對輸入輸出流進行緩沖,提高性能。
[WebMethod]
public List
BinaryReader bi = new BinaryReader(shpfo); //讀取shp文件
BinaryReader br = new BinaryReader(fs); //讀取shx文件
for(int n = 0;n < RecorderNumber;n++) //文件解析過程
{ ……
double[] pointsx = new double[Numpoints];
double[]pointsy = new double[Numpoints]; //定義數組
for(int z = 0;z < Numpoints;z++) //for循環讀取
{ ……
pointtemp.X = br.ReadDouble();
pointtemp.Y = br.ReadDouble();
shpstr+= "["+ pointtemp.X+ ","+ pointtemp.Y+ "],";
}
list.Add(shpstr);//存入List集合
}
return list;
}
}
public List
{
BinaryReader br1 = new BinaryReader(dbfo); //讀取二進制文件
…
DataRow dr = dt.NewRow();
tempBytes = br1.ReadBytes(fieldLength[j]);
Regex regex = new Regex("\s+");
tempStr = regex.Replace(tempStr,"");
dt.Rows[i][j] = """+ tempStr+ """;
dbfstr = Regex.Split(result,"},"); //將解析后的屬性信息,轉字符串數組
…
return list; //將字符串數組遍歷,添加到集合后返回
}
調用WebService服務對文件流通過BinaryReader類的ReadInt和ReadByte等方法,根據文件結構以二進制流的方式對ShapeFile文件的.shp、.dbf、.shx文件進行解析,獲取點、線、面數據類型,以及點坐標和屬性文件。最后將解析后的數據以List

圖2 坐標List集合中每條數據格式圖Fig.2 Each data format chart in the coordinate List set

圖3 屬性List集合中每條數據格式圖Fig.3 Each data format graph in the attribute List collection
JSON是一種輕量級的數據交換格式[7],易于閱讀和編寫,同時也易于機器解析。每條JSON消息都是包含在大括號之內的,鍵值對組合中的鍵名寫在前面并用雙引號包含,鍵和值使用冒號分隔,冒號后面緊接著值,如:“key”:“value”;數組是用方括號包含起來的,如:[“zhou”,“zhang”]。相較于xml,JSON在傳輸的過程中采用了壓縮技術,傳輸的過程中更加節省寬帶而且傳輸更加高效。當大量的坐標信息以及屬性信息傳遞給前端瀏覽器的時候為了不引起瀏覽器卡頓,用戶等待時間過長,所以后臺需要將list集合進行遍歷,然后將字符串拼接成JSON格式的字符串再傳遞給前端。
以線的ShapeFile文件的解析為例。根據ArcGIS for JavaScript庫類提供的線的數據格式,將數據拼接成如下格式:
var myLine =[{ attributes:{“TNODE”:”7”,”LPOLY”:”2”},geometry:{"paths":[[[-91.40625,6.328125],[6.328125,19.3359375]]],
"spatialReference":{"wkid":4326}},
"symbol":{"color":[0,0,0,255],"width":1,"type":"esriSLS","style":"esriSLSSolid"}}];
核心代碼如下:
if(Convert.ToInt32(type)==3)
{
bdfstring1 = "{"+ ""attributes""+ ":"+bdfstring[i].ToString()+ "},"+ shapetype; //通過for循環,添加屬性信息
…
dbfstr = "["+ str.Remove(0,1)+ "]],"+ ""spatialReference""+ ":"+ "{"+ ""wkid""+ ":"+ 4326+ " }"+ "},"+ ""type""+ ":"+3+"},"; //通過for循環,添加坐標系信息
}
傳遞給前端的JSON字符串格式如圖4。
ArcGIS for JavaScript庫類是ESRI根據JavaScript技術實現的一組腳本,可以將ArcGIS Server提供的地圖資源和其它資源(ArcGIS Online)嵌入到Web應用中。有豐富的網絡資源、基于功能強大的Dojo JavaScript工具包、開發和部署都是完全免費的等優點。
前臺通過調用ArcGIS for JavaScript的GraphicLayer、Graphic和Geometry等接口對后臺還回的JSON數據進行解析。創建一個新的圖層,然后根據ArcGIS for JavaScript 框架提供的Graphic類new Graphic(geometry?,symbol?,attributes?,infoTemplate?)將解析后的數據傳遞給瀏覽器渲染展示。通過InfoTemplate類new InfoTemplate(JSON)將屬性信息展示出來。

圖5 中國省級行政區界線讀取Fig.5 Reading of China’s provincial administrative boundaries

圖6 中國省級行政區界線面讀取Fig.6 Reading the boundary surface of provincial administrative regions in China

圖4 傳遞給前端的JSON字符串格式Fig.4 JSON string format passed to the front end
//設置線的顏色寬度
var myLine = {"symbol":{ "color":[0,0,0,255],"width":2,"type":"esriSLS","style":"esriSLSSolid" }};
//設置屬性窗口
var infoTemplate = new mapAPI.InfoTemplate("Attributes",JSON.parse(attri));
//創建一個新的圖層
var countyLayer = new map.GraphicsLayer();
//將圖層添加到地圖上
countyLayer.add(gra);
map.addLayer(countyLayer);
本文采用中國省級行政區界.shp矢量地圖數據,用來驗證編寫的系統讀寫ShapeFile 圖形文件的功能。采用谷歌瀏覽器,利用VS 2012,在.NET 4.5的環境下完成。Esri提供的底圖是WGS 84坐標系。
(1) 讀取中國省級行政區界.shp,如圖5所示。
(2) 讀取中國省級行政區界.shp面信息,以及屬性信息,如圖6所示。
(3) 中國省級行政區界屬性信息的讀取展示,如圖7所示。
本文首先介紹了Shapefile圖形文件的基本結構,根據ShapeFile文件的結構在.NET環境下利用 Microsoft Visual Studio2012平臺開發了可以展示ShapeFile圖形及其屬性信息的WebGIS系統,加深了對網絡傳輸、JSON字符串、以二進制文件流的方式解析文件、WebGIS系統開發以及ShapeFile文件結構等的理解,對后期各學者建設WebGIS平臺提供借鑒。

圖7 中國省級行政區界屬性信息顯示Fig.7 Attribute information display of provincial administrative boundaries in China