第10章 - 实用工具类详解
第10章 - 实用工具类详解
10.1 工具类概述
OGU4J提供了一系列实用工具类,位于com.znlgis.ogu4j.utils包:
| 工具类 | 功能 | 主要用途 |
|---|---|---|
ZipUtil |
ZIP压缩/解压 | Shapefile打包、数据分发 |
EncodingUtil |
编码检测 | 中文属性读取 |
SortUtil |
自然排序 | 带数字的字符串排序 |
NumUtil |
数字格式化 | 去除科学计数法 |
此外,还有位于com.znlgis.ogu4j.engine.util包的引擎工具类:
| 工具类 | 功能 | 主要用途 |
|---|---|---|
ShpUtil |
Shapefile工具 | Shapefile相关操作 |
PostgisUtil |
PostGIS工具 | 数据库连接管理 |
OgrUtil |
OGR工具 | GDAL/OGR相关 |
GeotoolsUtil |
GeoTools工具 | GeoTools相关 |
GdalCmdUtil |
GDAL命令行 | 命令行工具封装 |
10.2 ZipUtil - ZIP压缩解压
10.2.1 类定义
/**
* ZIP压缩/解压工具类
* 基于Zip4j库实现
*/
public class ZipUtil {
/**
* 压缩文件夹(使用系统默认编码)
*/
public static void zip(File folder, String zipPath);
/**
* 压缩文件夹(指定编码)
*/
public static void zip(File folder, String zipPath, Charset charset);
/**
* 解压文件(使用系统默认编码)
*/
public static void unzip(String zipPath, String destPath);
/**
* 解压文件(指定编码)
*/
public static void unzip(String zipPath, String destPath, Charset charset);
}
10.2.2 基本使用
import com.znlgis.ogu4j.utils.ZipUtil;
import java.io.File;
import java.nio.charset.StandardCharsets;
// 压缩文件夹
File folder = new File("D:/data/shapefile_folder");
ZipUtil.zip(folder, "D:/output/data.zip");
// 指定UTF-8编码(推荐,避免中文乱码)
ZipUtil.zip(folder, "D:/output/data.zip", StandardCharsets.UTF_8);
// 解压文件
ZipUtil.unzip("D:/data/data.zip", "D:/output/extracted");
// 指定编码解压
ZipUtil.unzip("D:/data/data.zip", "D:/output/extracted", StandardCharsets.UTF_8);
10.2.3 Shapefile打包
public class ShapefilePackager {
/**
* 打包Shapefile(包含所有关联文件)
*/
public static void packageShapefile(String shpPath, String zipPath) {
File shpFile = new File(shpPath);
String baseName = shpFile.getName().replace(".shp", "");
File folder = shpFile.getParentFile();
// 创建临时目录
File tempDir = new File(System.getProperty("java.io.tmpdir"),
"shp_" + System.currentTimeMillis());
tempDir.mkdirs();
try {
// 复制所有相关文件
String[] extensions = {".shp", ".shx", ".dbf", ".prj", ".cpg", ".sbn", ".sbx"};
for (String ext : extensions) {
File srcFile = new File(folder, baseName + ext);
if (srcFile.exists()) {
Files.copy(srcFile.toPath(),
new File(tempDir, srcFile.getName()).toPath());
}
}
// 压缩
ZipUtil.zip(tempDir, zipPath, StandardCharsets.UTF_8);
} finally {
// 清理临时目录
deleteDirectory(tempDir);
}
}
/**
* 解压Shapefile并返回shp文件路径
*/
public static String unpackShapefile(String zipPath, String destDir) {
ZipUtil.unzip(zipPath, destDir, StandardCharsets.UTF_8);
// 查找shp文件
File dir = new File(destDir);
File[] shpFiles = dir.listFiles((d, name) -> name.endsWith(".shp"));
if (shpFiles != null && shpFiles.length > 0) {
return shpFiles[0].getAbsolutePath();
}
throw new DataSourceException("ZIP包中未找到Shapefile");
}
}
10.2.4 处理中文路径
public class ChinesePathHandler {
public static void zipWithChinesePath(String folderPath, String zipPath) {
try {
// 使用GBK编码处理Windows中文路径
ZipUtil.zip(new File(folderPath), zipPath, Charset.forName("GBK"));
} catch (Exception e) {
// 回退到UTF-8
ZipUtil.zip(new File(folderPath), zipPath, StandardCharsets.UTF_8);
}
}
}
10.3 EncodingUtil - 编码检测
10.3.1 类定义
/**
* 文件编码检测工具类
*/
public class EncodingUtil {
/**
* 自动检测文件编码
* @param file 要检测的文件
* @return 检测到的字符集
*/
public static Charset getFileEncoding(File file);
}
10.3.2 基本使用
import com.znlgis.ogu4j.utils.EncodingUtil;
import java.io.File;
import java.nio.charset.Charset;
// 检测文件编码
File file = new File("D:/data/sample.txt");
Charset charset = EncodingUtil.getFileEncoding(file);
System.out.println("检测到编码: " + charset.name());
// 使用检测到的编码读取文件
String content = new String(Files.readAllBytes(file.toPath()), charset);
10.3.3 Shapefile编码检测
public class ShapefileEncodingHelper {
/**
* 获取Shapefile的DBF文件编码
*/
public static Charset getDbfEncoding(String shpPath) {
// 首先检查cpg文件
String cpgPath = shpPath.replace(".shp", ".cpg");
File cpgFile = new File(cpgPath);
if (cpgFile.exists()) {
try {
String encoding = new String(Files.readAllBytes(cpgFile.toPath())).trim();
return Charset.forName(encoding);
} catch (Exception e) {
// cpg文件无效,继续检测
}
}
// 检测dbf文件编码
String dbfPath = shpPath.replace(".shp", ".dbf");
File dbfFile = new File(dbfPath);
if (dbfFile.exists()) {
return EncodingUtil.getFileEncoding(dbfFile);
}
// 默认返回UTF-8
return StandardCharsets.UTF_8;
}
/**
* 创建cpg文件
*/
public static void createCpgFile(String shpPath, Charset charset) {
String cpgPath = shpPath.replace(".shp", ".cpg");
try {
Files.write(Paths.get(cpgPath), charset.name().getBytes());
} catch (IOException e) {
throw new DataSourceException("创建cpg文件失败", e);
}
}
}
10.3.4 批量编码转换
public class EncodingConverter {
/**
* 转换文件编码
*/
public static void convertEncoding(String inputPath, String outputPath,
Charset sourceCharset, Charset targetCharset) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get(inputPath));
String content = new String(bytes, sourceCharset);
Files.write(Paths.get(outputPath), content.getBytes(targetCharset));
}
/**
* 批量转换目录下所有文本文件的编码
*/
public static void batchConvert(String dir, Charset targetCharset) {
File folder = new File(dir);
File[] files = folder.listFiles((d, name) ->
name.endsWith(".txt") || name.endsWith(".csv"));
if (files == null) return;
for (File file : files) {
Charset sourceCharset = EncodingUtil.getFileEncoding(file);
if (!sourceCharset.equals(targetCharset)) {
try {
String content = new String(
Files.readAllBytes(file.toPath()), sourceCharset);
Files.write(file.toPath(), content.getBytes(targetCharset));
System.out.printf("已转换: %s (%s -> %s)%n",
file.getName(), sourceCharset.name(), targetCharset.name());
} catch (IOException e) {
System.err.printf("转换失败: %s - %s%n", file.getName(), e.getMessage());
}
}
}
}
}
10.4 SortUtil - 自然排序
10.4.1 类定义
/**
* 自然排序工具类
* 正确处理包含数字的字符串排序
*/
public class SortUtil {
/**
* 比较两个字符串(自然排序)
* @return 负数表示s1<s2,0表示相等,正数表示s1>s2
*/
public static int compareString(String s1, String s2);
}
10.4.2 问题背景
普通字符串排序的问题:
// 普通排序
List<String> files = Arrays.asList(
"第1章", "第10章", "第2章", "第20章", "第3章");
Collections.sort(files);
// 结果: [第1章, 第10章, 第2章, 第20章, 第3章] // 错误!
// 自然排序
files.sort(SortUtil::compareString);
// 结果: [第1章, 第2章, 第3章, 第10章, 第20章] // 正确!
10.4.3 基本使用
import com.znlgis.ogu4j.utils.SortUtil;
// 比较两个字符串
int result = SortUtil.compareString("第5章", "第10章");
System.out.println(result); // 负数,因为5 < 10
// 排序列表
List<String> items = Arrays.asList(
"文件1", "文件10", "文件2", "文件100", "文件20");
items.sort(SortUtil::compareString);
// 结果: [文件1, 文件2, 文件10, 文件20, 文件100]
// 排序文件名
List<String> fileNames = Arrays.asList(
"layer_1.shp", "layer_10.shp", "layer_2.shp", "layer_3.shp");
fileNames.sort(SortUtil::compareString);
// 结果: [layer_1.shp, layer_2.shp, layer_3.shp, layer_10.shp]
10.4.4 对象排序
public class FeatureSorter {
/**
* 按名称自然排序要素
*/
public static void sortByName(List<OguFeature> features, String fieldName) {
features.sort((f1, f2) -> {
String name1 = Optional.ofNullable(f1.getValue(fieldName))
.map(Object::toString).orElse("");
String name2 = Optional.ofNullable(f2.getValue(fieldName))
.map(Object::toString).orElse("");
return SortUtil.compareString(name1, name2);
});
}
/**
* 按FID自然排序
*/
public static void sortByFid(List<OguFeature> features) {
features.sort((f1, f2) -> SortUtil.compareString(f1.getFid(), f2.getFid()));
}
}
// 使用示例
List<OguFeature> features = layer.getFeatures();
FeatureSorter.sortByName(features, "NAME");
FeatureSorter.sortByFid(features);
10.4.5 自定义比较器
public class NaturalOrderComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
return SortUtil.compareString(s1, s2);
}
}
// 使用
List<String> items = new ArrayList<>(Arrays.asList("a10", "a2", "a1"));
items.sort(new NaturalOrderComparator());
// 或者使用TreeSet
TreeSet<String> sortedSet = new TreeSet<>(new NaturalOrderComparator());
sortedSet.addAll(items);
10.5 NumUtil - 数字格式化
10.5.1 类定义
/**
* 数字格式化工具类
*/
public class NumUtil {
/**
* 去除科学计数法显示
* @param value 数值
* @return 普通数字字符串
*/
public static String getPlainString(double value);
}
10.5.2 问题背景
Java默认会用科学计数法显示大数或小数:
double large = 12340000000.0;
System.out.println(large); // 1.234E10
double small = 0.00000123;
System.out.println(small); // 1.23E-6
10.5.3 基本使用
import com.znlgis.ogu4j.utils.NumUtil;
// 大数
double large = 12340000000.0;
String result = NumUtil.getPlainString(large);
System.out.println(result); // 12340000000
// 小数
double small = 0.00000123;
String result2 = NumUtil.getPlainString(small);
System.out.println(result2); // 0.00000123
// 坐标值
double x = 500000.123456789;
System.out.println(NumUtil.getPlainString(x)); // 500000.123456789
10.5.4 坐标格式化
public class CoordinateFormatter {
/**
* 格式化WKT中的坐标值
*/
public static String formatWktCoordinates(String wkt, int decimals) {
// 简化示例:格式化WKT中的数字
Pattern pattern = Pattern.compile("-?\\d+\\.\\d+");
Matcher matcher = pattern.matcher(wkt);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
double value = Double.parseDouble(matcher.group());
String formatted = String.format("%." + decimals + "f", value);
matcher.appendReplacement(sb, formatted);
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 格式化坐标
*/
public static String formatCoordinate(double x, double y, int decimals) {
String format = "%." + decimals + "f";
return String.format("(%s, %s)",
String.format(format, x),
String.format(format, y));
}
}
10.6 GdalCmdUtil - GDAL命令行工具
10.6.1 类定义
/**
* GDAL命令行工具封装
*/
public class GdalCmdUtil {
/**
* 获取FileGDB的数据结构
* @param gdbPath GDB文件路径
* @return GDB数据结构模型
*/
public static GdbGroupModel getGdbDataStructure(String gdbPath);
}
10.6.2 获取GDB结构
import com.znlgis.ogu4j.engine.util.GdalCmdUtil;
import com.znlgis.ogu4j.engine.model.GdbGroupModel;
// 获取GDB数据结构
GdbGroupModel structure = GdalCmdUtil.getGdbDataStructure("D:/data/sample.gdb");
// 遍历要素数据集
System.out.println("=== 要素数据集 ===");
for (String dataset : structure.getFeatureDatasets()) {
System.out.println(" " + dataset);
}
// 遍历图层
System.out.println("=== 图层 ===");
for (String layer : structure.getLayers()) {
System.out.println(" " + layer);
}
10.6.3 GdbGroupModel
/**
* GDB数据结构模型
*/
@Data
public class GdbGroupModel {
/**
* 要素数据集列表
*/
private List<String> featureDatasets;
/**
* 图层(要素类)列表
*/
private List<String> layers;
/**
* 表列表
*/
private List<String> tables;
}
10.7 ShpUtil - Shapefile工具
10.7.1 常用方法
/**
* Shapefile工具类
*/
public class ShpUtil {
/**
* 获取Shapefile的字段列表
*/
public static List<OguField> getFields(String shpPath);
/**
* 获取Shapefile的范围
*/
public static Envelope getBounds(String shpPath);
/**
* 获取Shapefile的要素数量
*/
public static int getFeatureCount(String shpPath);
/**
* 创建空的Shapefile
*/
public static void createEmptyShapefile(String shpPath,
SimpleFeatureType featureType);
}
10.7.2 使用示例
import com.znlgis.ogu4j.engine.util.ShpUtil;
// 获取字段信息
List<OguField> fields = ShpUtil.getFields("D:/data/cities.shp");
for (OguField field : fields) {
System.out.printf("%s (%s)%n", field.getName(), field.getDataType());
}
// 获取范围
Envelope bounds = ShpUtil.getBounds("D:/data/cities.shp");
System.out.printf("范围: (%.4f, %.4f) - (%.4f, %.4f)%n",
bounds.getMinX(), bounds.getMinY(),
bounds.getMaxX(), bounds.getMaxY());
// 获取要素数量
int count = ShpUtil.getFeatureCount("D:/data/cities.shp");
System.out.println("要素数量: " + count);
10.8 PostgisUtil - PostGIS工具
10.8.1 常用方法
/**
* PostGIS工具类
*/
public class PostgisUtil {
/**
* 解析连接字符串
*/
public static DbConnBaseModel parseConnectionString(String connStr);
/**
* 构建连接字符串
*/
public static String buildConnectionString(String host, int port,
String database, String user, String password, String schema);
/**
* 测试连接
*/
public static boolean testConnection(DbConnBaseModel conn);
}
10.8.2 使用示例
import com.znlgis.ogu4j.engine.util.PostgisUtil;
import com.znlgis.ogu4j.engine.model.DbConnBaseModel;
// 解析连接字符串
String connStr = "PG: host=localhost port=5432 dbname=gisdb " +
"user=postgres password=123456 active_schema=public";
DbConnBaseModel conn = PostgisUtil.parseConnectionString(connStr);
System.out.println("Host: " + conn.getHost());
System.out.println("Port: " + conn.getPort());
System.out.println("Database: " + conn.getDatabase());
System.out.println("User: " + conn.getUser());
System.out.println("Schema: " + conn.getSchema());
// 构建连接字符串
String newConnStr = PostgisUtil.buildConnectionString(
"192.168.1.100", 5432, "production", "admin", "secret", "gis");
System.out.println(newConnStr);
// 测试连接
if (PostgisUtil.testConnection(conn)) {
System.out.println("连接成功");
} else {
System.out.println("连接失败");
}
10.8.3 DbConnBaseModel
/**
* 数据库连接模型
*/
@Data
public class DbConnBaseModel {
private String host;
private int port;
private String database;
private String user;
private String password;
private String schema;
}
10.9 综合案例
10.9.1 数据打包下载服务
public class DataPackageService {
/**
* 打包指定图层供下载
*/
public String packageForDownload(String shpPath, String outputDir) {
// 1. 创建临时目录
String tempDir = System.getProperty("java.io.tmpdir") +
"/download_" + System.currentTimeMillis();
new File(tempDir).mkdirs();
try {
// 2. 读取图层
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
shpPath,
null, null, null,
GisEngineType.GEOTOOLS
);
// 3. 写入临时目录
String tempShp = tempDir + "/" + layer.getName() + ".shp";
OguLayerUtil.writeLayer(
DataFormatType.SHP,
layer,
tempShp,
null, null,
GisEngineType.GEOTOOLS
);
// 4. 创建cpg文件(确保中文正确)
String cpgPath = tempShp.replace(".shp", ".cpg");
Files.write(Paths.get(cpgPath), "UTF-8".getBytes());
// 5. 压缩
String zipPath = outputDir + "/" + layer.getName() + ".zip";
ZipUtil.zip(new File(tempDir), zipPath, StandardCharsets.UTF_8);
return zipPath;
} finally {
// 6. 清理临时目录
deleteDirectory(new File(tempDir));
}
}
}
10.9.2 批量数据处理
public class BatchProcessor {
/**
* 批量处理目录下的所有Shapefile
*/
public void processDirectory(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;
}
// 按自然顺序处理
Arrays.sort(shpFiles, (f1, f2) ->
SortUtil.compareString(f1.getName(), f2.getName()));
new File(outputDir).mkdirs();
int success = 0;
int failed = 0;
for (File shpFile : shpFiles) {
System.out.println("处理: " + shpFile.getName());
try {
// 检测编码
Charset charset = EncodingUtil.getFileEncoding(
new File(shpFile.getPath().replace(".shp", ".dbf")));
System.out.println(" 编码: " + charset.name());
// 读取
OguLayer layer = OguLayerUtil.readLayer(
DataFormatType.SHP,
shpFile.getAbsolutePath(),
null, null, null,
GisEngineType.GEOTOOLS
);
// 处理...
processLayer(layer);
// 保存
String outputPath = outputDir + "/" +
shpFile.getName().replace(".shp", ".geojson");
OguLayerUtil.writeLayer(
DataFormatType.GEOJSON,
layer,
outputPath,
null, null,
GisEngineType.GEOTOOLS
);
success++;
} catch (Exception e) {
System.err.println(" 失败: " + e.getMessage());
failed++;
}
}
System.out.printf("%n处理完成: 成功 %d, 失败 %d%n", success, failed);
}
private void processLayer(OguLayer layer) {
// 自定义处理逻辑
}
}

浙公网安备 33010602011771号