如何用PHP读取大型GeoJSON文件并提取法国滑雪山地数据写入新文件
处理大型GeoJSON文件:提取法国滑雪山地数据
需求说明
现有一个310MB的全球滑雪山地GeoJSON文件(world-ski-mtn.geojson),需要在PHP中实现以下操作:读取文件,筛选出属性中iso3166_1Alpha2为"FR"的法国区域记录,将筛选结果写入新文件。
解决方案
针对大体积文件,优先选择低内存占用的流式处理方案;若服务器内存充足,也可使用更简洁的数组过滤方案。
方案一:流式逐行处理(低内存占用,适合超大型文件)
通过文件指针逐行读取,仅在捕获到完整的Feature对象时进行解析和筛选,避免一次性加载整个文件到内存:
<?php $inputFile = 'world-ski-mtn.geojson'; $outputFile = 'france-ski-mtn.geojson'; // 打开文件句柄 $inputHandle = fopen($inputFile, 'r'); $outputHandle = fopen($outputFile, 'w'); if (!$inputHandle || !$outputHandle) { die('文件打开失败'); } // 写入GeoJSON头部 fwrite($outputHandle, '{"type": "FeatureCollection", "features":['); $isFirstFeature = true; $capturingFeature = false; $currentFeatureContent = ''; while (($line = fgets($inputHandle)) !== false) { $trimmedLine = trim($line); // 检测Feature对象开始 if (str_contains($trimmedLine, '"type": "Feature"')) { $capturingFeature = true; $currentFeatureContent = $line; continue; } // 收集Feature内容直到对象结束 if ($capturingFeature) { $currentFeatureContent .= $line; if (str_ends_with($trimmedLine, '}') && !str_contains($trimmedLine, '{')) { $capturingFeature = false; // 解析当前Feature $feature = json_decode($currentFeatureContent, true); if (json_last_error() === JSON_ERROR_NONE) { // 筛选法国区域数据 if (isset($feature['properties']['location']['iso3166_1Alpha2']) && $feature['properties']['location']['iso3166_1Alpha2'] === 'FR') { // 处理Feature间的逗号分隔 if (!$isFirstFeature) { fwrite($outputHandle, ','); } fwrite($outputHandle, $currentFeatureContent); $isFirstFeature = false; } } $currentFeatureContent = ''; } } } // 写入GeoJSON尾部 fwrite($outputHandle, ']}'); // 关闭文件句柄 fclose($inputHandle); fclose($outputHandle); echo '筛选完成,结果已写入 ' . $outputFile; ?>
方案二:数组过滤(代码简洁,适合内存充足场景)
直接将整个文件加载为数组后过滤,代码更直观,但需要确保PHP的memory_limit足够(建议设置为512M或更高):
<?php $inputFile = 'world-ski-mtn.geojson'; $outputFile = 'france-ski-mtn.geojson'; // 读取并解析GeoJSON文件 $geoJsonContent = file_get_contents($inputFile); if ($geoJsonContent === false) { die('无法读取输入文件'); } $geoJsonData = json_decode($geoJsonContent, true); if (!isset($geoJsonData['features']) || !is_array($geoJsonData['features'])) { die('无效的GeoJSON格式'); } // 筛选法国区域的Feature $franceFeatures = array_filter($geoJsonData['features'], function($feature) { return isset($feature['properties']['location']['iso3166_1Alpha2']) && $feature['properties']['location']['iso3166_1Alpha2'] === 'FR'; }); // 构造新的FeatureCollection并写入文件 $resultData = [ 'type' => 'FeatureCollection', 'features' => array_values($franceFeatures) ]; if (file_put_contents($outputFile, json_encode($resultData, JSON_PRETTY_PRINT)) === false) { die('无法写入输出文件'); } echo '筛选完成,结果已写入 ' . $outputFile; ?>
关键说明
- 流式处理方案内存占用极低,适合处理几百MB甚至GB级的大型文件;
- 数组过滤方案代码更简洁,但依赖服务器内存,310MB文件需确保内存配置足够;
- 两种方案均保留原GeoJSON的数据结构,仅筛选符合条件的记录。
内容的提问来源于stack exchange,提问作者spreaderman
相关产品推荐
相关产品推荐

