简要说明
在java,利用jackcess 和 Esri Geometry API,解析mdb的矢量数据;主要注意的地方是,记录矢量表的矢量字段的几何信息是在GDB_GeomColumns中;另外目前暂时无法找到原本数据的坐标系epsg code
maven依赖
<dependency>
<groupId>com.healthmarketscience.jackcess</groupId>
<artifactId>jackcess</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>com.esri.geometry</groupId>
<artifactId>esri-geometry-api</artifactId>
<version>2.2.4</version>
</dependency>
样例代码
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.OperatorImportFromESRIShape;
import com.esri.core.geometry.ogc.OGCGeometry;
import com.healthmarketscience.jackcess.*;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class ReadMDBWithJackcess {
public static void main(String[] args) {
String mdbPath = "C:\\Users\\xxxx\\Desktop\\xxxx.mdb";
File file = new File(mdbPath);
try (Database db = DatabaseBuilder.open(file)) {
Map<String, Integer> tableFieldShapeTypeMap = getTableFieldShapeTypeMap(db);
// 获取表名列表
Set<String> tableNames = db.getTableNames();
for (String tableName : tableNames) {
// 打开表
Table table = db.getTable(tableName);
List<? extends Column> columns = table.getColumns();
for (Column column : columns) {
System.out.println(column.getName() + "\t" + column.getType().toString());
}
System.out.println();
// 读取所有行
for (Row row : table) {
for (Column column : columns) {
Object value = row.get(column.getName());
//DataType.OLE 类型代表几何类型
if (value instanceof byte[] && DataType.OLE.toString().equals(column.getType().toString())) {
// 如果是字节数组,尝试解析为几何对象
byte[] shapeBytes = (byte[]) value;
if (shapeBytes != null && shapeBytes.length > 0) {
// 使用 Esri Geometry API 解析二进制数据
ByteBuffer buffer = ByteBuffer.wrap(shapeBytes).order(java.nio.ByteOrder.LITTLE_ENDIAN);
buffer.rewind(); // 确保从头开始读取
try {
// 使用 OperatorImportFromESRIShape 解析 Shape 数据
OperatorImportFromESRIShape opImportFromESRIShape = (OperatorImportFromESRIShape) OperatorImportFromESRIShape.local();
Geometry.Type geometryTypeFromShapeType = getGeometryTypeFromShapeType(tableName, column.getName(), tableFieldShapeTypeMap);
Geometry esriGeometry = opImportFromESRIShape.execute(0, geometryTypeFromShapeType ,buffer);
if (esriGeometry != null) {
// 将 Esri 几何对象转换为 OGC 几何对象
OGCGeometry ogcGeometry = OGCGeometry.createFromEsriGeometry(esriGeometry, null);
if (ogcGeometry != null) {
// 输出 WKT 格式的几何数据
System.out.print(ogcGeometry.asText() + "\t");
} else {
System.out.print("无法创建 OGC 几何对象\t");
}
} else {
System.out.print("无效的几何数据\t");
}
} catch (Exception e) {
System.err.println("无法解析几何数据: " + e.getMessage());
}
} else {
System.out.print("无几何数据\t");
}
} else {
System.out.print(value + "\t");
}
}
System.out.println();
}
System.out.println("--------");
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取mdb某个矢量表的几何类型
* @param tableName
* @param fieldName
* @param tableFieldShapeTypeMap
* @return
*/
private static Geometry.Type getGeometryTypeFromShapeType(String tableName, String fieldName, Map<String, Integer> tableFieldShapeTypeMap) {
if (!tableFieldShapeTypeMap.containsKey(tableName + "." + fieldName)) {
return null;
}
Integer type = tableFieldShapeTypeMap.get(tableName + "." + fieldName);
//暂时只支持点、折线、面,也大致通过真实数据推断GDB_GeomColumns表中记录的几何类型
if (type.equals(1)) {
return Geometry.Type.Point;
}
if (type.equals(3)) {
return Geometry.Type.Polyline;
}
if (type.equals(4)) {
return Geometry.Type.Polygon;
}
return null;
}
private static Map<String, Integer> getTableFieldShapeTypeMap(Database db) throws IOException {
// 获取 GDB_GeomColumns 表
Table geomColumnsTable = db.getTable("GDB_GeomColumns");
// 创建一个映射,用于存储每个几何字段的几何类型
Map<String, Integer> geometryTypeMap = new HashMap<>();
// 读取 GDB_GeomColumns 表中的所有行
for (Row row : geomColumnsTable) {
String tableName = row.get("TableName").toString();
String fieldName = row.get("FieldName").toString();
int shapeType = ((Number) row.get("ShapeType")).intValue();
// 将几何字段和几何类型存储在映射中
geometryTypeMap.put(tableName + "." + fieldName, shapeType);
}
return geometryTypeMap;
}
}