Shapefile与GeoJSON互转工具 - 在线SHP转GeoJSON格式转换器

Shapefile ⇄ GeoJSON 互转工具

在线转换 Shapefile 与 GeoJSON 格式,支持双向转换和点、线、面要素

使用说明
支持 Shapefile 与 GeoJSON 双向转换,上传 .shp、.dbf 等文件自动解析并转换为目标格式。

上传 Shapefile 文件

点击或拖拽文件到此处上传

支持 .shp、.shx、.dbf、.prj、.cpg 格式(必需:.shp 和 .dbf)

格式说明

Shapefile 是由 Esri 开发的地理空间矢量数据格式,广泛应用于 GIS 软件中。一个完整的 Shapefile 由多个文件组成:

  • .shp - 存储几何图形(点、线、面)
  • .shx - 存储几何图形的索引
  • .dbf - 存储属性数据表
  • .prj - 存储坐标系统信息(可选)
  • .cpg - 存储字符编码信息(可选)

GeoJSON 是一种基于 JSON 的地理空间数据交换格式,易于解析和使用,是现代 Web 地图应用的标准格式。

支持的要素类型

  • Point - 点要素(如地标、兴趣点)
  • LineString - 线要素(如路径、轨迹)
  • Polygon - 面要素(如区域、边界)
  • MultiPoint - 多点要素
  • MultiLineString - 多线要素
  • MultiPolygon - 多面要素

注意事项

  • Shapefile 必须同时包含 .shp 和 .dbf 文件才能正确转换
  • 转换过程在浏览器本地完成,数据不会上传到服务器
  • 大文件(超过 50MB)可能导致浏览器卡顿,建议使用桌面 GIS 软件处理

代码实现

JavaScript

/**
 * Shapefile ⇄ GeoJSON 互转
 * 需要安装: npm install shpjs @mapbox/shp-write
 */
import getShapefile from 'shpjs';
import shpwrite from '@mapbox/shp-write';

// ==================== Shapefile 转 GeoJSON ====================

/**
 * 将单组 Shapefile 文件转换为 GeoJSON
 * @param {ArrayBuffer} shpBuffer - .shp 文件内容
 * @param {ArrayBuffer} [dbfBuffer] - .dbf 文件内容
 * @param {string} [prj] - .prj 文件内容(可选,坐标系信息)
 * @param {string} [cpg] - .cpg 文件内容(可选,字符编码)
 * @returns {Promise<Object>} GeoJSON FeatureCollection
 */
async function shpToGeoJSON(shpBuffer, dbfBuffer, prj, cpg) {
  return await getShapefile({ shp: shpBuffer, dbf: dbfBuffer, prj, cpg });
}

/**
 * 将多组 Shapefile 文件合并转换为单个 GeoJSON
 * @param {Array<{shp: ArrayBuffer, dbf?: ArrayBuffer, prj?: string, cpg?: string}>} groups
 * @returns {Promise<Object>} 合并后的 GeoJSON FeatureCollection
 */
async function batchShpToGeoJSON(groups) {
  const allFeatures = [];
  for (const g of groups) {
    const geojson = await shpToGeoJSON(g.shp, g.dbf, g.prj, g.cpg);
    if (geojson.features) allFeatures.push(...geojson.features);
    else if (geojson.type === 'Feature') allFeatures.push(geojson);
  }
  return { type: 'FeatureCollection', features: allFeatures };
}

// ==================== GeoJSON 转 Shapefile ====================

/**
 * 将 Multi* 几何类型展平为基本类型
 * @param {Object} geojson - GeoJSON FeatureCollection
 * @returns {Object} 展平后的 GeoJSON
 */
function flattenMultiGeometry(geojson) {
  const features = [];
  for (const feature of geojson.features) {
    const geom = feature.geometry;
    if (!geom) continue;
    const multiMap = { MultiPoint: 'Point', MultiLineString: 'LineString', MultiPolygon: 'Polygon' };
    if (multiMap[geom.type]) {
      for (const coords of geom.coordinates) {
        features.push({ ...feature, geometry: { type: multiMap[geom.type], coordinates: coords } });
      }
    } else {
      features.push(feature);
    }
  }
  return { type: 'FeatureCollection', features };
}

/**
 * 将 GeoJSON 转换为 Shapefile 并下载
 * @param {Object} geojson - GeoJSON FeatureCollection
 * @param {string} [filename] - 下载文件名(不含扩展名)
 */
function geoJSONToShp(geojson, filename = 'shapefile') {
  // 展平 Multi* 类型
  const flattened = flattenMultiGeometry(geojson);
  // @mapbox/shp-write 自动按几何类型拆分为不同图层
  const base64 = shpwrite.zip(flattened, {
    folder: filename,
    types: { point: 'points', polyline: 'lines', polygon: 'polygons' }
  });
  // base64 转 Blob 下载
  const bytes = atob(base64);
  const buffer = new Uint8Array(bytes.length);
  for (let i = 0; i < bytes.length; i++) buffer[i] = bytes.charCodeAt(i);
  const blob = new Blob([buffer], { type: 'application/zip' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename + '.zip';
  a.click();
  URL.revokeObjectURL(url);
}

// ==================== 使用示例 ====================

// Shapefile 转 GeoJSON
const shpFile = await fetch('data.shp').then(r => r.arrayBuffer());
const dbfFile = await fetch('data.dbf').then(r => r.arrayBuffer());
const result = await shpToGeoJSON(shpFile, dbfFile);
console.log(`要素数量: ${result.features.length}`);

// GeoJSON 转 Shapefile
geoJSONToShp(result, 'output');
        

Java

import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.data.simple.SimpleFeatureCollection;
import java.io.*;

/**
 * Shapefile 转 GeoJSON 工具类
 * 依赖: GeoTools (Maven: org.geotools:gt-shapefile, org.geotools:gt-geojson)
 */
public class ShpToGeoJSON {

    /**
     * 转换 Shapefile 为 GeoJSON
     * @param shpFile Shapefile 文件
     * @return GeoJSON 字符串
     */
    public static String convert(File shpFile) throws Exception {
        ShapefileDataStore store = new ShapefileDataStore(shpFile.toURI().toURL());
        SimpleFeatureCollection features = store.getFeatureSource().getFeatures();

        StringWriter writer = new StringWriter();
        new FeatureJSON().writeFeatureCollection(features, writer);

        store.dispose();
        return writer.toString();
    }

    public static void main(String[] args) throws Exception {
        File shpFile = new File("data.shp");
        String geoJSON = convert(shpFile);
        System.out.println("GeoJSON: " + geoJSON);
    }
}

Python

import geopandas as gpd
import json

def shp_to_geojson(shp_path: str, output_path: str = None) -> dict:
    """
    Shapefile 转 GeoJSON

    Args:
        shp_path: Shapefile 文件路径
        output_path: 输出 GeoJSON 文件路径(可选)

    Returns:
        GeoJSON 字典对象
    """
    # 读取 Shapefile
    gdf = gpd.read_file(shp_path)

    # 转换为 GeoJSON
    geojson = json.loads(gdf.to_json())

    # 保存到文件(可选)
    if output_path:
        gdf.to_file(output_path, driver='GeoJSON')

    return geojson

# 使用示例
if __name__ == '__main__':
    result = shp_to_geojson('data.shp', 'output.geojson')
    print(f"要素数量: {len(result['features'])}")
    print(json.dumps(result, indent=2, ensure_ascii=False))
        

评论 (0)

登录 后发表评论

暂无评论,快来发表第一条评论吧!