Java解析图形mdb矢量mdb
背景:项目中需要解析图形mdb,同事积累下的代码无法读取复杂图形;终于在某位大佬的博客下发现新的
解析方法,特此整理记录下。
原理:jackcess(assess提供解析mdb属性)、esri-geometry-api(esri提供解析二进制图形数据)
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>1.2.1</version>
</dependency>
读取测试代码
public static void main(String[] args) {
// 设置mdb文件路径
String mdbFilePath = "C:\\XXX.mdb";
File file = new File(mdbFilePath);
MDBReaderUtils readerUtils = new MDBReaderUtils();
MDBMsg mdbMsg = readerUtils.read(file, "DATA_TEMPLATE");// mdb中数据表名称
String epsg = mdbMsg.getEpsg();
List<Map<String, Object>> data = mdbMsg.getData();
System.out.println("epsg : " + epsg); // 坐标系
System.out.println("data : " + data.size()); // mdb数据
for (Map<String, Object> map : data) {
String objectid = MDBReaderUtils.getString(map.get("objectid")); // objectid
String wkt = MDBReaderUtils.getString(map.get("wkt")); // mdb中图形wkt
System.out.println(objectid + " -> " + wkt);
}
}
读取结果
MDBMsg
@Data
public class MDBMsg {
private String epsg; // 坐标系
private List<Map<String, Object>> data; // mdb数据
}
MDBReaderUtils
@Slf4j
public class MDBReaderUtils {
private final static Map<String, String> ESRI_EPSG_MAPPING = new HashMap<>();
static {
ESRI_EPSG_MAPPING.put("GCS_China_Geodetic_Coordinate_System_2000", "4490");
ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_40", "4528");
ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_39", "4527");
ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_41", "4529");
ESRI_EPSG_MAPPING.put("GCS_WGS_1984", "4326");
}
public MDBMsg read(MultipartFile multipartFile, String tableName) {
File file = null;
try {
String originalFilename = multipartFile.getOriginalFilename();
String[] filename = originalFilename.split("\\.");
file = File.createTempFile(filename[0], filename[1] + ".");
multipartFile.transferTo(file);
file.deleteOnExit();
} catch (IOException e) {
e.printStackTrace();
}
return read(file, tableName);
}
public MDBMsg read(File file, String tableName) {
MDBMsg mdbMsg = new MDBMsg();
try (Database db = DatabaseBuilder.open(file)) {
String epsg = getEpsg(db, tableName);
mdbMsg.setEpsg(epsg);
Map<String, Integer> tableFieldShapeTypeMap = getShapeFieldMap(db);
// 打开表
Table table = db.getTable(tableName);
List<? extends Column> columns = table.getColumns();
List<Map<String, Object>> data = new ArrayList<>();
// 读取所有行
for (Row row : table) {
Map<String, Object> map = new HashMap<>();
for (Column column : columns) {
String name = column.getName();
Object value = row.get(name);
//DataType.OLE 类型代表几何类型
if (value instanceof byte[] && DataType.OLE.toString().equals(column.getType().toString())) {
try {
// 如果是字节数组,尝试解析为几何对象
byte[] shapeBytes = (byte[]) value;
// 使用 Esri Geometry API 解析二进制数据
ByteBuffer buffer = ByteBuffer.wrap(shapeBytes).order(java.nio.ByteOrder.LITTLE_ENDIAN);
buffer.rewind(); // 确保从头开始读取
// 使用 OperatorImportFromESRIShape 解析 Shape 数据
OperatorImportFromESRIShape opImportFromESRIShape = OperatorImportFromESRIShape.local();
Geometry.Type geometryTypeFromShapeType = getGeometryTypeFromShapeType(tableName, column.getName(), tableFieldShapeTypeMap);
Geometry esriGeometry = opImportFromESRIShape.execute(0, geometryTypeFromShapeType ,buffer);
// 将 Esri 几何对象转换为 OGC 几何对象
OGCGeometry ogcGeometry = OGCGeometry.createFromEsriGeometry(esriGeometry, null);
// 输出 WKT 格式的几何数据
String wkt = ogcGeometry.asText();
map.put("wkt", wkt);
} catch (Exception e) {
System.err.println("无法解析几何数据: " + e.getMessage());
continue;
}
} else {
map.put(name, value);
}
}
data.add(map);
}
mdbMsg.setData(data);
} catch (Exception e) {
mdbMsg.setData(new ArrayList<>());
System.err.println(e.getMessage());
}
return mdbMsg;
}
/**
* 获取mdb某个矢量表的几何类型
* @param tableName
* @param fieldName
* @param tableFieldShapeTypeMap
* @return
*/
private 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 == 1) {
return Geometry.Type.Point;
}
if (type == 3) {
return Geometry.Type.Polyline;
}
if (type == 4) {
return Geometry.Type.Polygon;
}
return null;
}
private Map<String, Integer> getShapeFieldMap(Database db) {
try {
// 获取 GDB_GeomColumns 表
Table table = db.getTable("GDB_GeomColumns");
// 创建一个映射,用于存储每个几何字段的几何类型
Map<String, Integer> geometryTypeMap = new HashMap<>();
// 读取 GDB_GeomColumns 表中的所有行
for (Row row : table) {
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;
} catch (Exception e) {
log.error(e.getMessage());
return new HashMap<>();
}
}
private String getEpsg(Database db, String tName) {
String epsg = "";
try {
// 获取 GDB_GeomColumns 表
Table colTable = db.getTable("GDB_GeomColumns");
int srid = -1;
// 读取 GDB_GeomColumns 表中的所有行
for (Row row : colTable) {
String tableName = row.get("TableName").toString();
if (tName.equals(tableName)) {
srid = ((Number) row.get("SRID")).intValue();
break;
}
}
// 获取 GDB_SpatialRefs 表
Table refTable = db.getTable("GDB_SpatialRefs");
// 读取 GDB_SpatialRefs 表中的所有行
for (Row row : refTable) {
if (srid == ((Number) row.get("SRID")).intValue()) {
epsg = row.get("SRTEXT").toString().split(",")[0];
break;
}
}
for (Map.Entry<String, String> entry : ESRI_EPSG_MAPPING.entrySet()) {
if (epsg.contains(entry.getKey())) {
epsg = entry.getValue();
break;
}
}
return epsg;
} catch (Exception e) {
log.error(e.getMessage());
return epsg;
}
}
public static String getString(Object o) {
return Objects.isNull(o) ? null : o.toString();
}
public static Double getDouble(Object o) {
Double v = null;
try {
v = Double.valueOf(getString(o));
} catch (Exception var4) {
;
}
return v;
}
public static Integer getInteger(Object o) {
Integer v = null;
try {
v = Integer.valueOf(getString(o));
} catch (Exception var4) {
;
}
return v;
}
public static Long getLong(Object o) {
Long v = null;
try {
v = Long.valueOf(getString(o));
} catch (Exception var4) {
;
}
return v;
}
public static BigDecimal getBigDecimal(Object o) {
BigDecimal v = null;
try {
v = new BigDecimal(getString(o));
} catch (Exception var4) {
;
}
return v;
}
}
参考博文:https://blog.csdn.net/qq_41613913/article/details/142488569