В посте о программировании MapServer средствами .NET (C#) я упоминал .NET обертку (скачать ZIP) над библиотекой shapelib, которую я использовал для чтения и записи атрибутивной информации шейпфайла (SHP) и координат, хранящихся в файле DBF.
Приведенный ниже код для считывания атрибутов и координат может служить примером для операций считывания (запись через shapelib также возможна, но в этом посте не рассматривается) и, возможно, поможет сэкономить вам время при написании собственного кода:
/// <summary>
/// Чтение аттрибутивной информации в виде DataTable.
/// </summary>
/// <param name="shapeFilePath">The shape file path.</param>
/// <returns></returns>
public static DataTable ReadAttributes(string shapeFilePath)
{
// Table to store the data
DataTable attributes = new DataTable("Attributes");
// -------------------------------------------------------------------
// Чтение аттрибутивной информациии из DBF файла
// -------------------------------------------------------------------
string dbxFilePath = Path.ChangeExtension(shapeFilePath, ".dbf");
IntPtr hDbf = ShapeLib.DBFOpen(dbxFilePath, FileAccessMode.BinaryOpenForReadWrite);
if (!hDbf.Equals(IntPtr.Zero))
{
// verify the table structure
int recCount = ShapeLib.DBFGetRecordCount(hDbf);
int fieldCount = ShapeLib.DBFGetFieldCount(hDbf);
DataColumn[] columns = new DataColumn[fieldCount + 1];
// получаем информацию о столбцах
ShapeLib.DBFFieldType[] fieldTypes = new ShapeLib.DBFFieldType[fieldCount];
string[] fieldNames = new string[fieldCount];
int fieldWidth = 0;
int numDecimals = 0;
columns[0] = new DataColumn(PseudoColumnName, typeof (int));
for (int iField = 0; iField < fieldCount; iField++)
{
StringBuilder sb = new StringBuilder();
fieldTypes[iField] = ShapeLib.DBFGetFieldInfo(hDbf, iField, sb, ref fieldWidth, ref numDecimals);
fieldNames[iField] = sb.ToString();
string columnName = fieldNames[iField];
Type columnType = ConvertType(fieldTypes[iField]);
int fieldIndex = ShapeLib.DBFGetFieldIndex(hDbf, columnName);
columns[fieldIndex + 1] = new DataColumn(columnName, columnType);
}
// Добавляем реальные столбцы
attributes.Columns.AddRange(columns);
// получаем информацию о записях
for (int iShape = 0; iShape < recCount; iShape++)
{
DataRow row = attributes.NewRow();
// заполняем псевдо индекс
row[0] = iShape;
for (int iField = 0; iField < fieldCount; iField++)
{
int columnIndex = iField + 1; // с учетом псевдо индекса
if (ShapeLib.DBFIsAttributeNULL(hDbf, iShape, iField) != 0)
{
// Значения нет - присваиваем NULL
row[columnIndex] = DBNull.Value;
}
else
{
// Значение есть - присваиваем значение нужного типа
switch (fieldTypes[iField])
{
case (ShapeLib.DBFFieldType.FTString):
row[columnIndex] = ShapeLib.DBFReadStringAttribute(hDbf, iShape, iField);
break;
case (ShapeLib.DBFFieldType.FTDouble):
row[columnIndex] = ShapeLib.DBFReadDoubleAttribute(hDbf, iShape, iField);
break;
case (ShapeLib.DBFFieldType.FTLogical):
row[columnIndex] = ShapeLib.DBFReadLogicalAttribute(hDbf, iShape, iField);
break;
case (ShapeLib.DBFFieldType.FTInteger):
row[columnIndex] = ShapeLib.DBFReadIntegerAttribute(hDbf, iShape, iField);
break;
case (ShapeLib.DBFFieldType.FTDate):
row[columnIndex] = ShapeLib.DBFReadDateAttribute(hDbf, iShape, iField);
break;
default: // case (ShapeLib.DBFFieldType.FTInvalid):
row[columnIndex] = DBNull.Value;
break;
}
}
}
// Добавлем новую строку в таблицу
attributes.Rows.Add(row);
}
// release resources
ShapeLib.DBFClose(hDbf);
}
return attributes;
}
/// <summary>
/// Чтение координат слоя из SHP - шейп файла (пока не используется)
/// </summary>
/// <param name="shapeFilePath">Путь к шейпфайлу.</param>
/// <param name="objectIndex">Индект объекта в шейпфайле.</param>
/// <returns>Координаты слоя шейп файла в виде DataTable.</returns>
public static DataTable ReadCoordinates(string shapeFilePath, int objectIndex)
{
DataTable coordinates = new DataTable();
IntPtr hShp = ShapeLib.SHPOpen(shapeFilePath, FileAccessMode.BinaryOpenForReadWrite);
if (!hShp.Equals(IntPtr.Zero))
{
// - можно прочитать в цикле для каждого объекта в аттирбутивной информации
// - в этом примере метод получает индекс объекта параметром
// - для получения координат в цикле по всем объектам из шейп-файла - надо убрать
// - комментарии и изменить сигнатуру метода
// get shape info and verify shapes were created correctly
// double[] minB = new double[4];
// double[] maxB = new double[4];
// int nEntities = 0;
// ShapeLib.ShapeType shapeType = 0;
// ShapeLib.SHPGetInfo(hShp, ref nEntities, ref shapeType, minB, maxB);
// for (int objectIndex = 0; objectIndex < nEntities; i++)
{
// test SHPReadObject on the first shape
int iShape = objectIndex;
IntPtr pshpObj = ShapeLib.SHPReadObject(hShp, iShape);
// Get the SHPObject associated with our IntPtr pshpObj
// We create a new SHPObject in managed code, then use Marshal.PtrToStructure
// to copy the unmanaged memory pointed to by pshpObj into our managed copy.
ShapeLib.SHPObject shpObj = new ShapeLib.SHPObject();
Marshal.PtrToStructure(pshpObj, shpObj);
int nVertices = shpObj.nVertices;
coordinates.Columns.Add("X", typeof (double));
coordinates.Columns.Add("Y", typeof (double));
coordinates.Columns.Add("Z", typeof (double));
coordinates.Columns.Add("M", typeof (double));
double[] xCoord = new double[nVertices];
double[] yCoord = new double[nVertices];
double[] zCoord = new double[nVertices];
double[] mCoord = new double[nVertices];
// Recover the vertices for this shape. Use Marshal.Copy to copy the memory pointed
// to by shpObj.padfX and shpObj.padfX (each an IntPtr) to a actual array.
Marshal.Copy(shpObj.padfX, xCoord, 0, nVertices);
Marshal.Copy(shpObj.padfY, yCoord, 0, nVertices);
Marshal.Copy(shpObj.padfZ, zCoord, 0, nVertices);
Marshal.Copy(shpObj.padfM, mCoord, 0, nVertices);
// read vertices - XYZM per data row in table
for (int v = 0; v < nVertices; v++)
{
coordinates.Rows.Add(xCoord[v], yCoord[v], zCoord[v], mCoord[v]);
}
// free resources
// The .NET GC should clean up shpObj, but we'll force the cleanup anyway...
ShapeLib.SHPDestroyObject(pshpObj);
}
ShapeLib.SHPClose(hShp);
}
return coordinates;
}