第10章 - 实用工具类详解
第10章 - 实用工具类详解
10.1 工具类概述
OGU4Net提供了一系列实用工具类:
| 工具类 | 命名空间 | 功能 |
|---|---|---|
| EncodingUtil | Utils | 编码检测与转换 |
| ZipUtil | Utils | ZIP压缩与解压 |
| SortUtil | Utils | 自然排序 |
| NumUtil | Utils | 数字格式化 |
| ShpUtil | Engine.Util | Shapefile工具 |
| PostgisUtil | Engine.Util | PostGIS工具 |
| OgrUtil | Engine.Util | OGR辅助工具 |
| GdalCmdUtil | Engine.Util | GDAL命令行工具 |
10.2 EncodingUtil编码工具
10.2.1 功能概述
EncodingUtil 提供文件编码检测和转换功能,特别适用于处理中文编码问题:
using OpenGIS.Utils.Utils;
using System.Text;
10.2.2 检测文件编码
// 检测文件编码
string filePath = "data.txt";
Encoding encoding = EncodingUtil.GetFileEncoding(filePath);
Console.WriteLine($"检测到编码: {encoding.WebName}");
// 使用检测到的编码读取文件
string content = File.ReadAllText(filePath, encoding);
10.2.3 检测流编码
using var stream = File.OpenRead("data.txt");
Encoding encoding = EncodingUtil.GetFileEncoding(stream);
Console.WriteLine($"编码: {encoding.WebName}");
// 注意:此方法会重置流位置
10.2.4 检测字节数组编码
byte[] buffer = File.ReadAllBytes("data.txt");
Encoding encoding = EncodingUtil.DetectEncoding(buffer);
Console.WriteLine($"编码: {encoding.WebName}");
10.2.5 转换文件编码
// 将文件转换为UTF-8编码
EncodingUtil.ConvertFileEncoding("data.txt", Encoding.UTF8);
// 转换为GBK(需要先注册编码提供程序)
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
EncodingUtil.ConvertFileEncoding("data.txt", Encoding.GetEncoding("GBK"));
10.2.6 编码检测原理
/*
检测顺序:
1. BOM (Byte Order Mark) 检测
- UTF-8 BOM: EF BB BF
- UTF-16 LE: FF FE
- UTF-16 BE: FE FF
2. UTF-8 模式检测
- 检查多字节字符的有效性
3. GBK/GB2312 模式检测
- 检查双字节字符范围
4. 默认返回 UTF-8
*/
10.2.7 实际应用
// 处理Shapefile的DBF文件编码
public string ReadDbfField(string dbfPath, string fieldName)
{
// 检测DBF文件编码
var encoding = EncodingUtil.GetFileEncoding(dbfPath);
// 使用正确编码读取
var layer = ShpUtil.ReadShapefile(
Path.ChangeExtension(dbfPath, ".shp"),
encoding);
// 获取字段值
var feature = layer.Features.FirstOrDefault();
return feature?.GetValue(fieldName)?.ToString() ?? "";
}
10.3 ZipUtil压缩工具
10.3.1 压缩文件夹
using OpenGIS.Utils.Utils;
// 压缩整个文件夹
ZipUtil.Zip("source_folder/", "output.zip");
// 指定编码压缩
ZipUtil.Zip("source_folder/", "output.zip", Encoding.UTF8);
10.3.2 解压文件
// 解压到指定目录
ZipUtil.Unzip("archive.zip", "output_folder/");
// 指定编码解压(处理中文文件名)
ZipUtil.Unzip("archive.zip", "output_folder/", Encoding.GetEncoding("GBK"));
10.3.3 压缩多个文件
// 压缩指定的多个文件
var files = new[]
{
"file1.txt",
"file2.shp",
"file3.dbf"
};
ZipUtil.CompressFiles(files, "archive.zip");
10.3.4 Shapefile打包
// 将Shapefile的所有组成文件打包
public void ZipShapefile(string shpPath, string zipPath)
{
var baseName = Path.GetFileNameWithoutExtension(shpPath);
var dir = Path.GetDirectoryName(shpPath) ?? ".";
var extensions = new[] { ".shp", ".shx", ".dbf", ".prj", ".cpg", ".sbn", ".sbx" };
var files = extensions
.Select(ext => Path.Combine(dir, baseName + ext))
.Where(File.Exists)
.ToList();
ZipUtil.CompressFiles(files, zipPath);
Console.WriteLine($"已打包 {files.Count} 个文件到 {zipPath}");
}
10.4 SortUtil排序工具
10.4.1 自然排序
标准字符串排序可能不符合预期:
标准排序: file1, file10, file2, file9
自然排序: file1, file2, file9, file10
10.4.2 使用自然排序
using OpenGIS.Utils.Utils;
// 文件名排序
var files = new[] { "file10.txt", "file2.txt", "file1.txt", "file9.txt" };
var sorted = SortUtil.NaturalSort(files, f => f);
foreach (var file in sorted)
{
Console.WriteLine(file);
}
// 输出:
// file1.txt
// file2.txt
// file9.txt
// file10.txt
10.4.3 排序对象列表
// 对象列表按某属性自然排序
class FileInfo
{
public string Name { get; set; }
public long Size { get; set; }
}
var fileInfos = new List<FileInfo>
{
new() { Name = "chapter10.md", Size = 1024 },
new() { Name = "chapter2.md", Size = 512 },
new() { Name = "chapter1.md", Size = 256 }
};
var sorted = SortUtil.NaturalSort(fileInfos, f => f.Name);
foreach (var file in sorted)
{
Console.WriteLine(file.Name);
}
// 输出:
// chapter1.md
// chapter2.md
// chapter10.md
10.4.4 处理测量点号
// 国土测量点号排序
var pointNumbers = new[] { "J1", "J10", "J2", "J11", "J3" };
var sorted = SortUtil.NaturalSort(pointNumbers, p => p);
// 结果: J1, J2, J3, J10, J11
10.5 NumUtil数字工具
10.5.1 避免科学计数法
using OpenGIS.Utils.Utils;
// 小数可能显示为科学计数法
double small = 0.00000123;
Console.WriteLine(small.ToString()); // 输出: 1.23E-06
// 使用NumUtil避免科学计数法
string plain = NumUtil.GetPlainString(small);
Console.WriteLine(plain); // 输出: 0.00000123
10.5.2 大数值处理
// 大数也可能显示为科学计数法
double large = 123456789012345.0;
Console.WriteLine(large.ToString()); // 可能: 1.23456789012345E+14
string plain = NumUtil.GetPlainString(large);
Console.WriteLine(plain); // 输出完整数字
10.5.3 坐标输出
// 输出坐标时避免科学计数法
public string FormatCoordinate(double x, double y, double? z = null)
{
var xStr = NumUtil.GetPlainString(x);
var yStr = NumUtil.GetPlainString(y);
if (z.HasValue)
{
var zStr = NumUtil.GetPlainString(z.Value);
return $"POINT Z ({xStr} {yStr} {zStr})";
}
return $"POINT ({xStr} {yStr})";
}
10.6 ShpUtil Shapefile工具
10.6.1 读写Shapefile
using OpenGIS.Utils.Engine.Util;
// 读取Shapefile(自动处理编码)
var layer = ShpUtil.ReadShapefile("data.shp");
// 指定编码读取
var gbkLayer = ShpUtil.ReadShapefile("data.shp", Encoding.GetEncoding("GBK"));
// 写入Shapefile
ShpUtil.WriteShapefile(layer, "output.shp", Encoding.UTF8);
10.6.2 编码处理
// 获取Shapefile编码
Encoding encoding = ShpUtil.GetShapefileEncoding("data.shp");
Console.WriteLine($"Shapefile编码: {encoding.WebName}");
// 创建CPG文件
ShpUtil.CreateCpgFile("data.shp", Encoding.UTF8);
10.6.3 获取边界
// 获取Shapefile的边界范围
var envelope = ShpUtil.GetShapefileBounds("data.shp");
if (envelope != null)
{
Console.WriteLine($"X范围: {envelope.MinX} - {envelope.MaxX}");
Console.WriteLine($"Y范围: {envelope.MinY} - {envelope.MaxY}");
}
10.6.4 修复Shapefile
// 修复可能损坏的Shapefile
// 通过读取后重新写入来修复一些问题
ShpUtil.RepairShapefile("damaged.shp");
10.7 PostgisUtil PostGIS工具
10.7.1 连接字符串构建
using OpenGIS.Utils.Engine.Util;
// 构建PostGIS连接字符串
string connStr = PostgisUtil.BuildConnectionString(
host: "localhost",
database: "mydb",
user: "postgres",
password: "secret",
port: 5432
);
Console.WriteLine(connStr);
// 输出: PG:host=localhost dbname=mydb user=postgres password=secret port=5432
10.7.2 连接测试
// 测试PostGIS连接
bool canConnect = PostgisUtil.TestConnection(connStr);
if (canConnect)
{
Console.WriteLine("连接成功");
}
else
{
Console.WriteLine("连接失败");
}
10.8 GdalCmdUtil GDAL命令工具
10.8.1 执行GDAL命令
using OpenGIS.Utils.Engine.Util;
// 获取ogr2ogr命令路径
string ogr2ogr = GdalCmdUtil.GetOgr2OgrPath();
// 执行ogr2ogr转换
GdalCmdUtil.ExecuteOgr2Ogr(
inputPath: "input.shp",
outputPath: "output.geojson",
outputFormat: "GeoJSON"
);
10.8.2 坐标转换命令
// 使用ogr2ogr进行坐标转换
GdalCmdUtil.ReprojectLayer(
inputPath: "wgs84.shp",
outputPath: "cgcs2000.shp",
targetSrs: "EPSG:4490"
);
10.9 综合应用示例
10.9.1 批量处理工具
public class BatchProcessor
{
public void ProcessDirectory(string inputDir, string outputDir)
{
// 确保输出目录存在
Directory.CreateDirectory(outputDir);
// 获取所有Shapefile并自然排序
var shpFiles = Directory.GetFiles(inputDir, "*.shp");
var sorted = SortUtil.NaturalSort(shpFiles, f => Path.GetFileName(f));
foreach (var shpFile in sorted)
{
try
{
// 检测编码
var encoding = ShpUtil.GetShapefileEncoding(shpFile);
Console.WriteLine($"处理: {Path.GetFileName(shpFile)} (编码: {encoding.WebName})");
// 读取
var layer = ShpUtil.ReadShapefile(shpFile, encoding);
// 处理...
ProcessLayer(layer);
// 写入
var outputPath = Path.Combine(
outputDir,
Path.GetFileNameWithoutExtension(shpFile) + ".geojson");
OguLayerUtil.WriteLayer(DataFormatType.GEOJSON, layer, outputPath);
}
catch (Exception ex)
{
Console.Error.WriteLine($"处理失败: {shpFile} - {ex.Message}");
}
}
}
private void ProcessLayer(OguLayer layer)
{
// 添加面积字段
layer.AddField(new OguField
{
Name = "Area",
DataType = FieldDataType.DOUBLE
});
foreach (var feature in layer.Features)
{
if (!string.IsNullOrEmpty(feature.Wkt))
{
var area = GeometryUtil.AreaWkt(feature.Wkt);
feature.SetValue("Area", area);
}
}
}
}
10.9.2 数据打包工具
public class DataPackager
{
public void PackageProject(string projectDir, string outputZip)
{
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);
try
{
// 复制并处理Shapefile
foreach (var shpFile in Directory.GetFiles(projectDir, "*.shp"))
{
// 检测编码
var encoding = ShpUtil.GetShapefileEncoding(shpFile);
// 复制相关文件
var baseName = Path.GetFileNameWithoutExtension(shpFile);
var extensions = new[] { ".shp", ".shx", ".dbf", ".prj" };
foreach (var ext in extensions)
{
var srcFile = Path.Combine(projectDir, baseName + ext);
if (File.Exists(srcFile))
{
File.Copy(srcFile, Path.Combine(tempDir, baseName + ext));
}
}
// 创建CPG文件确保编码正确
ShpUtil.CreateCpgFile(Path.Combine(tempDir, baseName + ".shp"), encoding);
}
// 打包
ZipUtil.Zip(tempDir, outputZip);
Console.WriteLine($"项目已打包: {outputZip}");
}
finally
{
// 清理临时目录
if (Directory.Exists(tempDir))
{
Directory.Delete(tempDir, true);
}
}
}
}
10.9.3 坐标格式化工具
public class CoordinateFormatter
{
public string FormatTxtLine(OguCoordinate coord, int zoneNumber)
{
// 使用NumUtil避免科学计数法
var pointNumber = coord.PointNumber ?? "";
var ringNumber = coord.RingNumber ?? "";
var x = NumUtil.GetPlainString(coord.X);
var y = NumUtil.GetPlainString(coord.Y);
var z = coord.Z.HasValue ? NumUtil.GetPlainString(coord.Z.Value) : "";
var remark = coord.Remark ?? "";
return $"{pointNumber}\t{ringNumber}\t{x}\t{y}\t{z}\t{remark}";
}
public void ExportToTxt(OguLayer layer, string outputPath)
{
var lines = new List<string>();
// 添加头部
lines.Add("点号\t圈号\tX\tY\tZ\t备注");
foreach (var feature in layer.Features)
{
if (string.IsNullOrEmpty(feature.Wkt)) continue;
var coord = OguCoordinate.FromWkt(feature.Wkt);
coord.PointNumber = feature.GetValue("点号")?.ToString();
coord.RingNumber = feature.GetValue("圈号")?.ToString();
coord.Remark = feature.GetValue("备注")?.ToString();
lines.Add(FormatTxtLine(coord, 39));
}
// 使用UTF-8编码保存
File.WriteAllLines(outputPath, lines, Encoding.UTF8);
}
}
10.10 小结
本章介绍了OGU4Net的实用工具类:
- EncodingUtil:编码检测和转换,解决中文乱码问题
- ZipUtil:ZIP压缩和解压,支持中文文件名
- SortUtil:自然排序,正确处理文件名中的数字
- NumUtil:数字格式化,避免科学计数法
- ShpUtil:Shapefile专用工具,编码处理和修复
- PostgisUtil:PostGIS连接和操作工具
- GdalCmdUtil:GDAL命令行工具封装
这些工具类解决了GIS开发中的常见问题,提高了开发效率。

浙公网安备 33010602011771号