Rust GIS数据处理库shapefile的使用,高效读写和操作ESRI Shapefile格式的地理空间数据

Rust GIS数据处理库shapefile的使用,高效读写和操作ESRI Shapefile格式的地理空间数据

基本用法示例

// 创建Shapefile读取器
let mut reader = shapefile::Reader::from_path(filename).unwrap();

// 遍历所有形状和记录
for result in reader.iter_shapes_and_records() {
    let (shape, record) = result.unwrap();
    println!("Shape: {}, records: ", shape);
    
    // 打印每条记录
    for (name, value) in record {
        println!("\t{}: {:?}, ", name, value);
    }
    println!();
}

完整示例代码

use shapefile::{Reader, Shape};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 指定Shapefile文件路径
    let filename = "path/to/your/shapefile.shp";
    
    // 创建Shapefile读取器
    let mut reader = Reader::from_path(filename)?;
    
    // 获取Shapefile的类型信息
    let shape_type = reader.header().shape_type;
    println!("Shapefile类型: {:?}", shape_type);
    
    // 遍历所有形状和属性记录
    for result in reader.iter_shapes_and_records() {
        let (shape, record) = result?;
        
        match shape {
            Shape::Point(point) => {
                println!("点: ({}, {})", point.x, point.y);
            }
            Shape::Polyline(polyline) => {
                println!("多段线,共{}部分", polyline.parts.len());
                for part in &polyline.parts {
                    println!(" - 部分有{}个点", part.len());
                }
            }
            Shape::Polygon(polygon) => {
                println!("多边形,共{}部分", polygon.parts.len());
                for part in &polygon.parts {
                    println!(" - 部分有{}个点", part.len());
                }
            }
            _ => println!("其他形状类型: {:?}", shape),
        }
        
        // 打印属性记录
        println!("属性记录:");
        for (field_name, field_value) in record {
            println!("  {}: {:?}", field_name, field_value);
        }
        println!("------------------");
    }
    
    Ok(())
}

安装

在项目中添加shapefile依赖,在Cargo.toml中添加:

shapefile = "0.7.0"

或者运行命令:

cargo add shapefile

特性

  • 支持读取和写入ESRI Shapefile格式
  • 通过dbase crate支持.dbf属性表
  • 支持多种几何类型:点、线、多边形等
  • 提供迭代器接口方便遍历要素

1 回复

下面是根据提供的内容整理的完整示例代码,包含形状文件的读取、写入以及属性数据处理:

完整示例:城市点数据Shapefile处理

use shapefile::{Point, Shape, ShapeReader, ShapeWriter};
use shapefile::dbase::{FieldName, FieldValue, FieldType, Record, TableWriterBuilder};

fn main() -> Result<(), shapefile::Error> {
    // 示例1:读取并打印城市点数据
    read_city_points()?;
    
    // 示例2:创建带属性的城市Shapefile
    create_city_shapefile_with_attributes()?;
    
    // 示例3:批量生成并写入大量点数据
    batch_generate_points()?;
    
    Ok(())
}

/// 示例1:读取城市点数据并打印信息
fn read_city_points() -> Result<(), shapefile::Error> {
    println!("\n--- 读取城市点数据 ---");
    
    // 读取Shapefile和对应的DBF文件
    let mut reader = ShapeReader::from_path("data/cities.shp")?;
    let shapes = reader.read_shapes()?;
    let records = reader.read_records()?;
    
    // 关联几何图形和属性数据
    for (shape, record) in shapes.iter().zip(records.iter()) {
        if let Shape::Point(point) = shape {
            if let Some(name) = record.get("NAME") {
                println!("城市: {}, 坐标: ({}, {})", name, point.x, point.y);
            }
        }
    }
    
    Ok(())
}

/// 示例2:创建带属性的城市Shapefile
fn create_city_shapefile_with_attributes() -> Result<(), shapefile::Error> {
    println!("\n--- 创建带属性的城市Shapefile ---");
    
    // 创建几何数据 - 两个城市点
    let points = vec![
        Shape::Point(Point::new(116.404, 39.915)),  // 北京
        Shape::Point(Point::new(121.474, 31.230)),  // 上海
    ];

    // 创建属性字段
    let name_field = FieldName::try_from("NAME")?;
    let pop_field = FieldName::try_from("POPULATION")?;
    let province_field = FieldName::try_from("PROVINCE")?;
    
    // 创建属性记录
    let records = vec![
        Record::from_data(vec![
            (name_field.clone(), FieldValue::Character(Some("Beijing".to_string()))),
            (pop_field.clone(), FieldValue::Numeric(Some(2171.0))), // 万人
            (province_field.clone(), FieldValue::Character(Some("Beijing".to_string()))),
        ]),
        Record::from_data(vec![
            (name_field.clone(), FieldValue::Character(Some("Shanghai".to_string()))),
            (pop_field.clone(), FieldValue::Numeric(Some(2424.0))), // 万人
            (province_field.clone(), FieldValue::Character(Some("Shanghai".to_string()))),
        ]),
    ];
    
    // 创建Shapefile写入器
    let mut shape_writer = ShapeWriter::from_path("output/china_cities.shp")?;
    for point in &points {
        shape_writer.write_shape(point)?;
    }
    
    // 创建DBF表写入器
    let mut table_writer = TableWriterBuilder::new()
        .add_field(name_field, FieldType::Character(50))   // 城市名称字段
        .add_field(pop_field, FieldType::Float)           // 人口数字段
        .add_field(province_field, FieldType::Character(20)) // 省份字段
        .build_with_dbf_path("output/china_cities.dbf")?;
    
    for record in &records {
        table_writer.write_record(record)?;
    }
    
    println!("成功创建带属性的城市Shapefile");
    Ok(())
}

/// 示例3:批量生成并写入大量点数据
fn batch_generate_points() -> Result<(), shapefile::Error> {
    println!("\n--- 批量生成点数据 ---");
    
    let mut writer = ShapeWriter::from_path("output/random_points.shp")?;
    let mut shapes = Vec::new();
    
    // 生成1000个随机点
    for i in 0..1000 {
        shapes.push(Shape::Point(Point::new(
            rand::random::<f64>() * 360.0 - 180.0,  // 经度 -180到180
            rand::random::<f64>() * 180.0 - 90.0    // 纬度 -90到90
        )));
    }
    
    // 批量写入
    writer.write_shapes(&shapes)?;
    
    println!("成功生成1000个随机点数据");
    Ok(())
}

示例说明

  1. 读取城市点数据

    • 从"data/cities.shp"读取点数据
    • 同时读取关联的.dbf属性表
    • 打印每个城市的名称和坐标
  2. 创建带属性的城市Shapefile

    • 创建北京和上海两个城市的点数据
    • 为每个城市添加名称、人口和省份属性
    • 同时生成.shp和.dbf文件
  3. 批量生成点数据

    • 生成1000个随机地理坐标点
    • 使用批量写入提高性能
    • 保存到random_points.shp文件

运行准备

  1. 创建Cargo项目并添加依赖:
[dependencies]
shapefile = "0.4.0"
rand = "0.8"
  1. 创建data目录并放入测试数据(如cities.shp等)

  2. 创建output目录用于保存生成的文件

这个完整示例展示了shapefile库的主要功能,包括数据读取、属性处理和批量写入操作,适用于大多数GIS数据处理场景。

回到顶部