第06章 - 数据格式转换实战
第06章 - 数据格式转换实战
6.1 格式转换概述
6.1.1 支持的格式
OGU4J支持以下主流GIS数据格式:
| 格式 | 扩展名 | 读取 | 写入 | 推荐引擎 | 说明 |
|---|---|---|---|---|---|
| Shapefile | .shp | ✅ | ✅ | GeoTools/GDAL | 最通用的矢量格式 |
| GeoJSON | .geojson/.json | ✅ | ✅ | GeoTools | Web友好的JSON格式 |
| FileGDB | .gdb | ✅ | ✅ | GDAL | ESRI地理数据库 |
| PostGIS | - | ✅ | ✅ | GeoTools | PostgreSQL空间扩展 |
| 国土TXT | .txt | ✅ | ✅ | 内置 | 自然资源部门格式 |
6.1.2 格式类型枚举
/**
* 数据格式类型枚举
*/
public enum DataFormatType {
/**
* Shapefile格式
* 包含.shp、.dbf、.shx、.prj等文件
*/
SHP("Shapefile", ".shp"),
/**
* GeoJSON格式
* JSON格式的地理数据
*/
GEOJSON("GeoJSON", ".geojson"),
/**
* Esri FileGDB格式
* ESRI的文件地理数据库
*/
FILEGDB("FileGDB", ".gdb"),
/**
* PostGIS格式
* PostgreSQL数据库中的空间表
*/
POSTGIS("PostGIS", null);
private final String name;
private final String extension;
// 构造函数和getter方法
}
6.1.3 转换流程
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 源数据格式 │ --> │ OguLayer │ --> │ 目标数据格式 │
│ (SHP/GeoJSON) │ │ (统一模型) │ │ (GDB/PostGIS) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
▼ ▼ ▼
OguLayerUtil 数据处理 OguLayerUtil
.readLayer() (过滤/转换) .writeLayer()
6.2 Shapefile处理
6.2.1 读取Shapefile
基础读取
import com.znlgis.ogu4j.datasource.OguLayerUtil;
import com.znlgis.ogu4j.engine.model.layer.OguLayer;
import com.znlgis.ogu4j.engine.enums.DataFormatType;
import com.znlgis.ogu4j.engine.enums.GisEngineType;
// 简单读取
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
"D:/data/cities.shp",
null, // layerName(Shapefile可为null)
null, // 属性过滤
null, // 空间过滤
GisEngineType.GEOTOOLS
);
System.out.println("图层名称: " + layer.getName());
System.out.println("要素数量: " + layer.getFeatureCount());
System.out.println("字段数量: " + layer.getFields().size());
带属性过滤的读取
// 使用CQL表达式过滤
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
"D:/data/cities.shp",
null,
"POPULATION > 1000000", // 人口大于100万的城市
null,
GisEngineType.GEOTOOLS
);
// 复杂过滤条件
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
"D:/data/cities.shp",
null,
"LEVEL = 1 AND PROVINCE = '广东'", // 一级城市且在广东省
null,
GisEngineType.GEOTOOLS
);
// 模糊匹配
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
"D:/data/cities.shp",
null,
"NAME LIKE '%市'", // 名称以"市"结尾
null,
GisEngineType.GEOTOOLS
);
带空间过滤的读取
// 使用WKT定义过滤范围
String filterWkt = "POLYGON((116 39, 116 40, 117 40, 117 39, 116 39))";
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
"D:/data/cities.shp",
null,
null,
filterWkt, // 只读取与此范围相交的要素
GisEngineType.GEOTOOLS
);
// 同时使用属性和空间过滤
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
"D:/data/cities.shp",
null,
"LEVEL = 1", // 一级城市
filterWkt, // 且在指定范围内
GisEngineType.GEOTOOLS
);
6.2.2 写入Shapefile
基础写入
// 假设已有OguLayer对象
OguLayer layer = createSampleLayer();
// 写入Shapefile
OguLayerUtil.writeLayer(
DataFormatType.SHP,
layer,
"D:/output/result.shp",
null, // layerName
null, // options
GisEngineType.GEOTOOLS
);
完整示例:创建并写入Shapefile
public class ShapefileExample {
public static void main(String[] args) {
// 1. 创建图层
OguLayer layer = new OguLayer();
layer.setName("中国城市");
layer.setWkid(4490); // CGCS2000
layer.setGeometryType(GeometryType.POINT);
// 2. 定义字段
List<OguField> fields = Arrays.asList(
createField("NAME", FieldDataType.STRING, 50),
createField("LEVEL", FieldDataType.INTEGER, null),
createField("POP", FieldDataType.DOUBLE, null)
);
layer.setFields(fields);
// 3. 添加要素
List<OguFeature> features = Arrays.asList(
createFeature("1", "北京", 1, 2154.2, "POINT(116.407 39.904)"),
createFeature("2", "上海", 1, 2428.1, "POINT(121.473 31.230)"),
createFeature("3", "广州", 2, 1881.0, "POINT(113.264 23.129)")
);
layer.setFeatures(features);
// 4. 写入Shapefile
OguLayerUtil.writeLayer(
DataFormatType.SHP,
layer,
"D:/output/cities.shp",
null, null,
GisEngineType.GEOTOOLS
);
System.out.println("Shapefile创建成功!");
}
private static OguField createField(String name, FieldDataType type, Integer length) {
OguField field = new OguField();
field.setName(name);
field.setDataType(type);
field.setLength(length);
return field;
}
private static OguFeature createFeature(String fid, String name,
int level, double pop, String wkt) {
OguFeature feature = new OguFeature();
feature.setFid(fid);
feature.setWkt(wkt);
feature.setValue("NAME", name);
feature.setValue("LEVEL", level);
feature.setValue("POP", pop);
return feature;
}
}
6.2.3 Shapefile注意事项
字段名长度限制
Shapefile的DBF文件限制字段名最长10个字符:
// 错误示例:字段名超过10字符
OguField field = new OguField();
field.setName("POPULATION_COUNT"); // 16字符,会被截断!
// 正确做法:使用短字段名
field.setName("POP_CNT"); // 7字符
field.setAlias("人口数量"); // 别名可以是中文
编码处理
// OGU4J自动处理中文编码
// 读取时会检测DBF编码
// 写入时默认使用UTF-8
// 如果遇到编码问题,检查cpg文件
// cities.cpg 应包含: UTF-8
坐标精度
// Shapefile坐标精度有限
// 对于高精度坐标,建议使用其他格式
// 检查坐标精度
OguFeature feature = layer.getFeatures().get(0);
String wkt = feature.getWkt();
System.out.println("坐标: " + wkt);
// 输出可能是: POINT(116.4070 39.9040) // 4位小数
6.3 GeoJSON处理
6.3.1 读取GeoJSON
// 读取GeoJSON文件
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.GEOJSON,
"D:/data/cities.geojson",
null, null, null,
GisEngineType.GEOTOOLS
);
// 遍历要素
for (OguFeature feature : layer.getFeatures()) {
System.out.printf("ID: %s, 名称: %s%n",
feature.getFid(),
feature.getValue("name"));
}
6.3.2 写入GeoJSON
// 将图层保存为GeoJSON
OguLayerUtil.writeLayer(
DataFormatType.GEOJSON,
layer,
"D:/output/result.geojson",
null, null,
GisEngineType.GEOTOOLS
);
6.3.3 GeoJSON与JSON字符串转换
// OguLayer转换为JSON字符串(非GeoJSON格式)
String json = layer.toJSON();
// 从JSON字符串恢复OguLayer
OguLayer restored = OguLayer.fromJSON(json);
// 如果需要标准GeoJSON格式,使用写入方法
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 写入到输出流...
String geojsonString = baos.toString("UTF-8");
6.3.4 GeoJSON特点
| 优点 | 缺点 |
|---|---|
| 人类可读 | 文件较大 |
| Web友好 | 不支持索引 |
| 无需多个文件 | 大数据量性能差 |
| 标准化格式 | 不适合频繁更新 |
6.4 FileGDB处理
6.4.1 FileGDB概述
FileGDB是ESRI的文件地理数据库格式,特点:
- 支持多个图层(要素类)
- 支持要素数据集(Feature Dataset)
- 支持域、关系类等高级功能
- 性能优于Shapefile
- 只能使用GDAL引擎处理
6.4.2 读取FileGDB
读取单个图层
// 确保GDAL可用
if (!GisEngineFactory.isEngineAvailable(GisEngineType.GDAL)) {
throw new RuntimeException("请先安装并配置GDAL");
}
// 读取指定图层
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.FILEGDB,
"D:/data/sample.gdb",
"Cities", // 图层名称
null, null,
GisEngineType.GDAL
);
带过滤条件读取
// 属性过滤
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.FILEGDB,
"D:/data/sample.gdb",
"Cities",
"POPULATION > 500000",
null,
GisEngineType.GDAL
);
// 空间过滤
String bbox = "POLYGON((116 39, 116 40, 117 40, 117 39, 116 39))";
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.FILEGDB,
"D:/data/sample.gdb",
"Districts",
null,
bbox,
GisEngineType.GDAL
);
6.4.3 写入FileGDB
创建新GDB并写入
// 写入新的FileGDB
OguLayerUtil.writeLayer(
DataFormatType.FILEGDB,
layer,
"D:/output/new.gdb", // GDB路径(会创建)
"Cities", // 图层名称
null,
GisEngineType.GDAL
);
写入到现有GDB
// 写入现有GDB中的新图层
OguLayerUtil.writeLayer(
DataFormatType.FILEGDB,
layer,
"D:/data/existing.gdb", // 现有GDB
"NewLayer", // 新图层名
null,
GisEngineType.GDAL
);
写入到要素数据集
// 使用options指定要素数据集
Map<String, Object> options = new HashMap<>();
options.put("featureDataset", "Boundaries"); // 要素数据集名称
OguLayerUtil.writeLayer(
DataFormatType.FILEGDB,
layer,
"D:/data/sample.gdb",
"Districts",
options, // 传入options
GisEngineType.GDAL
);
6.4.4 获取GDB结构
import com.znlgis.ogu4j.engine.util.GdalCmdUtil;
import com.znlgis.ogu4j.engine.model.GdbGroupModel;
// 获取GDB的完整结构
GdbGroupModel structure = GdalCmdUtil.getGdbDataStructure("D:/data/sample.gdb");
// 遍历要素数据集
for (String dataset : structure.getFeatureDatasets()) {
System.out.println("要素数据集: " + dataset);
}
// 遍历图层
for (String layer : structure.getLayers()) {
System.out.println("图层: " + layer);
}
6.5 PostGIS处理
6.5.1 PostGIS连接字符串
// 标准连接字符串格式
String connStr = "PG: host=localhost port=5432 dbname=gisdb " +
"user=postgres password=yourpassword active_schema=public";
// 各参数说明:
// host: 数据库主机地址
// port: 端口号,默认5432
// dbname: 数据库名称
// user: 用户名
// password: 密码
// active_schema: 活动模式,默认public
6.5.2 从PostGIS读取
String connStr = "PG: host=localhost port=5432 dbname=gisdb " +
"user=postgres password=123456 active_schema=public";
// 读取图层
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.POSTGIS,
connStr,
"cities", // 表名
null, null,
GisEngineType.GEOTOOLS
);
// 带过滤条件
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.POSTGIS,
connStr,
"cities",
"population > 1000000", // SQL WHERE条件
null,
GisEngineType.GEOTOOLS
);
6.5.3 写入PostGIS
String connStr = "PG: host=localhost port=5432 dbname=gisdb " +
"user=postgres password=123456 active_schema=public";
// 写入新表
OguLayerUtil.writeLayer(
DataFormatType.POSTGIS,
layer,
connStr,
"new_cities", // 表名(会创建)
null,
GisEngineType.GEOTOOLS
);
6.5.4 PostGIS工具类
import com.znlgis.ogu4j.engine.util.PostgisUtil;
// 解析连接字符串
DbConnBaseModel conn = PostgisUtil.parseConnectionString(connStr);
System.out.println("Host: " + conn.getHost());
System.out.println("Database: " + conn.getDatabase());
// 构建连接字符串
String connStr = PostgisUtil.buildConnectionString(
"localhost", 5432, "gisdb", "postgres", "123456", "public"
);
6.6 国土TXT格式
6.6.1 格式说明
国土TXT是自然资源部门使用的坐标文本格式:
[属性描述]
要素名称=土地1
土地代码=123456
坐标系=2000国家大地坐标系
...
[地块坐标]
J1,1,500000.123,4000000.456
J2,1,500100.123,4000000.456
J3,1,500100.123,4000100.456
J4,1,500000.123,4000100.456
J1,1,500000.123,4000000.456
6.6.2 读取国土TXT
import com.znlgis.ogu4j.datasource.GtTxtUtil;
// 读取TXT文件
OguLayer layer = GtTxtUtil.loadTxt("D:/data/land.txt", null);
// 获取元数据
OguLayerMetadata metadata = layer.getMetadata();
System.out.println("坐标系: " + metadata.getCoordinateSystemName());
System.out.println("分带方式: " + metadata.getZoneDivision());
// 获取坐标点
for (OguFeature feature : layer.getFeatures()) {
List<OguCoordinate> coords = feature.getCoordinates();
for (OguCoordinate coord : coords) {
System.out.printf("点号: %s, X: %.3f, Y: %.3f%n",
coord.getPointNo(), coord.getX(), coord.getY());
}
}
6.6.3 写入国土TXT
import com.znlgis.ogu4j.datasource.GtTxtUtil;
import com.znlgis.ogu4j.engine.model.layer.OguLayerMetadata;
// 准备元数据
OguLayerMetadata metadata = new OguLayerMetadata();
metadata.setDataSource("自然资源部");
metadata.setCoordinateSystemName("2000国家大地坐标系");
metadata.setZoneDivision("3"); // 3度分带
metadata.setProjectionType("高斯克吕格");
metadata.setMeasureUnit("米");
// 写入TXT
int zoneNumber = 39; // 带号
GtTxtUtil.saveTxt(layer, "D:/output/result.txt", metadata, null, zoneNumber);
6.7 格式转换实战
6.7.1 Shapefile转GeoJSON
public class ShpToGeoJson {
public static void convert(String shpPath, String geojsonPath) {
// 1. 读取Shapefile
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
shpPath,
null, null, null,
GisEngineType.GEOTOOLS
);
System.out.println("读取完成,要素数量: " + layer.getFeatureCount());
// 2. 写入GeoJSON
OguLayerUtil.writeLayer(
DataFormatType.GEOJSON,
layer,
geojsonPath,
null, null,
GisEngineType.GEOTOOLS
);
System.out.println("转换完成: " + geojsonPath);
}
public static void main(String[] args) {
convert("D:/data/cities.shp", "D:/output/cities.geojson");
}
}
6.7.2 Shapefile转FileGDB
public class ShpToGdb {
public static void convert(String shpPath, String gdbPath, String layerName) {
// 1. 读取Shapefile
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
shpPath,
null, null, null,
GisEngineType.GEOTOOLS // 用GeoTools读取
);
// 2. 写入FileGDB
OguLayerUtil.writeLayer(
DataFormatType.FILEGDB,
layer,
gdbPath,
layerName,
null,
GisEngineType.GDAL // 必须用GDAL写入
);
System.out.println("转换完成");
}
public static void main(String[] args) {
convert("D:/data/cities.shp", "D:/output/sample.gdb", "Cities");
}
}
6.7.3 FileGDB转PostGIS
public class GdbToPostgis {
public static void convert(String gdbPath, String layerName,
String postgisConnStr, String tableName) {
// 1. 从FileGDB读取
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.FILEGDB,
gdbPath,
layerName,
null, null,
GisEngineType.GDAL
);
// 2. 写入PostGIS
OguLayerUtil.writeLayer(
DataFormatType.POSTGIS,
layer,
postgisConnStr,
tableName,
null,
GisEngineType.GEOTOOLS
);
System.out.println("转换完成,表名: " + tableName);
}
public static void main(String[] args) {
String connStr = "PG: host=localhost port=5432 dbname=gisdb " +
"user=postgres password=123456 active_schema=public";
convert("D:/data/sample.gdb", "Cities", connStr, "cities_imported");
}
}
6.7.4 批量格式转换
public class BatchConverter {
/**
* 批量将Shapefile转换为GeoJSON
*/
public static void batchConvert(String inputDir, String outputDir) {
File dir = new File(inputDir);
File[] shpFiles = dir.listFiles((d, name) -> name.endsWith(".shp"));
if (shpFiles == null || shpFiles.length == 0) {
System.out.println("未找到Shapefile文件");
return;
}
// 创建输出目录
new File(outputDir).mkdirs();
int success = 0;
int failed = 0;
for (File shpFile : shpFiles) {
String baseName = shpFile.getName().replace(".shp", "");
String outputPath = outputDir + "/" + baseName + ".geojson";
try {
// 读取
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
shpFile.getAbsolutePath(),
null, null, null,
GisEngineType.GEOTOOLS
);
// 写入
OguLayerUtil.writeLayer(
DataFormatType.GEOJSON,
layer,
outputPath,
null, null,
GisEngineType.GEOTOOLS
);
System.out.println("✓ " + baseName);
success++;
} catch (Exception e) {
System.out.println("✗ " + baseName + ": " + e.getMessage());
failed++;
}
}
System.out.printf("%n转换完成: 成功 %d, 失败 %d%n", success, failed);
}
public static void main(String[] args) {
batchConvert("D:/data/shapefiles", "D:/output/geojson");
}
}
6.7.5 带坐标转换的格式转换
public class ConvertWithReproject {
/**
* 转换格式并进行坐标系转换
*/
public static void convertAndReproject(String inputPath, String outputPath,
int targetWkid) {
// 1. 读取数据
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
inputPath,
null, null, null,
GisEngineType.GEOTOOLS
);
System.out.println("原坐标系: WKID " + layer.getWkid());
// 2. 坐标转换
if (layer.getWkid() != null && layer.getWkid() != targetWkid) {
layer = CrsUtil.reproject(layer, targetWkid);
System.out.println("已转换到: WKID " + targetWkid);
}
// 3. 保存
OguLayerUtil.writeLayer(
DataFormatType.GEOJSON,
layer,
outputPath,
null, null,
GisEngineType.GEOTOOLS
);
System.out.println("保存完成: " + outputPath);
}
public static void main(String[] args) {
// 将投影坐标转换为地理坐标
convertAndReproject(
"D:/data/projected.shp",
"D:/output/geographic.geojson",
4490 // CGCS2000地理坐标系
);
}
}
6.8 错误处理
6.8.1 常见异常
try {
OguLayer layer = OguLayerUtil.readLayer(...);
} catch (DataSourceException e) {
// 数据源问题:文件不存在、连接失败等
System.err.println("数据源错误: " + e.getMessage());
} catch (FormatParseException e) {
// 格式解析问题:CQL语法错误、WKT格式错误等
System.err.println("格式错误: " + e.getMessage());
} catch (EngineNotSupportedException e) {
// 引擎问题:GDAL未安装、格式不支持等
System.err.println("引擎错误: " + e.getMessage());
} catch (OguException e) {
// 其他OGU4J异常
System.err.println("处理错误: " + e.getMessage());
}
6.8.2 最佳实践
public class SafeConverter {
public static boolean safeConvert(String input, String output,
DataFormatType inputFormat, DataFormatType outputFormat) {
// 1. 验证输入
if (input == null || output == null) {
System.err.println("路径不能为空");
return false;
}
// 2. 检查输入文件
if (inputFormat != DataFormatType.POSTGIS) {
File inputFile = new File(input);
if (!inputFile.exists()) {
System.err.println("输入文件不存在: " + input);
return false;
}
}
// 3. 选择引擎
GisEngineType readEngine = GisEngineFactory.getRecommendedEngine(inputFormat);
GisEngineType writeEngine = GisEngineFactory.getRecommendedEngine(outputFormat);
// 4. 检查引擎可用性
if (!GisEngineFactory.isEngineAvailable(readEngine)) {
System.err.println("读取引擎不可用: " + readEngine);
return false;
}
if (!GisEngineFactory.isEngineAvailable(writeEngine)) {
System.err.println("写入引擎不可用: " + writeEngine);
return false;
}
// 5. 执行转换
try {
OguLayer layer = OguLayerUtil.readLayer(
inputFormat, input, null, null, null, readEngine
);
layer.validate(); // 验证数据
OguLayerUtil.writeLayer(
outputFormat, layer, output, null, null, writeEngine
);
return true;
} catch (Exception e) {
System.err.println("转换失败: " + e.getMessage());
e.printStackTrace();
return false;
}
}
}

浙公网安备 33010602011771号