news 2026/10/26 3:34:29

全国铁路SHP数据处理:坐标系投影、拓扑打断与最短路构建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
全国铁路SHP数据处理:坐标系投影、拓扑打断与最短路构建

简介:全国铁路SHP数据.zip面向地理信息、城市规划、交通工程等方向的学习者与研究人员,提供可载入ArcGIS、QGIS等软件的全国铁路线路和2016年高铁站点矢量数据,便于完成线路分布分析、站点选址、区域交通研究及专题制图。压缩包共12个文件,大小约11.37MB,以shp、dbf、prj、shx等格式为主,分别承载空间几何、属性字段、坐标定义与索引信息,便于准确配准和快速读取;其中属性表可用于线路与站点信息查询,投影文件有助于统一空间参考、减少图层错位。资源已有2769人学习下载,适合GIS入门练习、课程设计、制图作业及科研前期底图准备,对交通网络与城市研究具有参考价值。结合铁路线长度统计、高铁站分布模式识别、最近站点查询等空间分析,并与人口、经济等数据叠加,可服务区域发展研究与规划决策。

1. 全国铁路SHP数据不是底图:先想清楚你要拿它算什么

把「全国铁路SHP数据.zip」解压出来,多数人第一件事是拖进 QGIS 看一眼,觉得线画得挺全,然后就关掉了。这份东西的本质是一组线状要素矢量数据:每条记录是一条折线几何,配一行属性,说明这条线叫什么、属于哪类线路。它能干的事很具体——做路网距离与可达性计算、做站点接驳缓冲区、给物流路径做可视化底图、在内网离线环境里画一张能缩放到全国的铁路示意图。它不能干的事同样具体:没有车次时刻、没有客货运量、没有上下行区分,几何上也未必真的连通。所以第一步不是画图,是决定你要拿它算里程、算最短路,还是只当底图。三种用途对数据质量的要求差着一个数量级,先定用途再动手,能省掉后面一大半返工。

2. 拆包先验骨架:SHP 五件套与 DBF 字段的 10 字符困局

2.1 .shp/.shx/.dbf/.prj/.cpg 各管什么,少一个会出什么事

Shapefile 从来不是一个文件,而是一组同名的伴生文件。压缩包里如果只挑了.shp解出来,后面所有诡异现象都能从这里找到根。先把每个角色认清楚:

扩展名作用缺失后的典型症状
.shp存几何坐标直接打不开,没有任何兜底
.shx几何索引,记录每条记录在 shp 中的偏移部分工具能靠扫描重建,但读取速度骤降,大文件容易失败
.dbf属性表,dBASE 格式只剩几何没有名字,无法按线路筛选
.prj坐标系定义,通常是 ESRI WKT软件按未知坐标系处理,长度单位变成「度」
.cpg声明 dbf 的字符编码中文属性大概率乱码
.sbn/.sbx空间索引,可选不影响正确性,只影响查询速度

.prj和.cpg是重灾区,因为它们「看起来不重要」。一份全国范围的铁路线数据,.prj里通常写着地理坐标系(经纬度)而不是投影坐标系,这意味着你打开就量长度,量出来的是度数。.cpg里如果写的是 UTF-8,而 dbf 里实际存的是 GBK,那打开就是一堆问号——这种编码错配在跨软件流转的数据包里极其常见。

判断方法很朴素:解压后先ls一遍,看伴生文件是否齐全;再用文本编辑器打开.prj和.cpg直接看内容,.cpg一般就一行UTF-8或GBK/936。这一步花不了一分钟,但能提前排除后面一半的排查工作量。

2.2 用 geopandas 一次读出图层、字段与几何体检报告

不要急着画图,先出一份体检报告。下面的脚本把图层名、坐标系、字段、几何类型分布、无效几何、空几何一次性打出来,跑完你就知道这份数据能不能直接进下一步。

import geopandas as gpd import pyogrio SHP = "全国铁路.shp" # 1) 先看不读几何,速度极快,确认图层名与几何类型 print(pyogrio.list_layers(SHP)) # 2) 指定编码读取,避免中文乱码;engine 用 pyogrio 比 fiona 快数倍 gdf = gpd.read_file(SHP, engine="pyogrio", encoding="UTF-8") print("坐标系:", gdf.crs) print("要素数:", len(gdf)) print("字段:", list(gdf.columns)) # 3) 几何体检 report = { "几何类型分布": gdf.geom_type.value_counts().to_dict(), "空几何": int(gdf.geometry.is_empty.sum()), "无效几何": int((~gdf.geometry.is_valid).sum()), "自相交": int((~gdf.geometry.is_simple).sum()), } for k, v in report.items(): print(f"{k}: {v}")

这段代码有三个关键参数值得说清楚。encoding必须和.cpg声明一致;如果.cpg写的是 GBK 而你传 UTF-8,读出来照样是乱码,此时改成encoding="GBK"再试,两种都试一遍是正确的排查姿势。engine="pyogrio"是 GDAL 的向量读写封装,对全国量级的线数据,读取速度通常比默认引擎快三到五倍,代价是需要额外装包。第三步的is_valid检查很关键:铁路线数据在拼接来源不同时期的数据时,常出现自相交、重复点、零长度段,这些几何在后续打断和构图时会直接抛异常,或者更糟——静默产生错误的拓扑。

如果体检报告里无效几何占比超过千分之一,不要急着make_valid一把梭。先按几何类型分组,看看无效集中在哪一类线路上,往往是某一段外部导入数据的坐标精度问题,定位到源头再修比全局修复安全得多。

2.3 字段名被截断之后:建一张映射表把 NAME/TYPE 翻译回来

dBASE 格式对字段名的限制是 10 个字符,而 Shapefile 规范里字段名还只能包含字母数字下划线。中文原始字段名在导出成 Shapefile 时,要么被截断成NAME_1、NAME_2,要么被转成拼音首字母。你拿到的属性表里出现一堆XZQHMC、XLMC这种缩写,不是作者故弄玄虚,是格式限制的产物。

处理办法是建一张映射表,把缩写、字段位置和业务含义对上,再统一改名。判断哪个字段对应什么,最可靠的方式是抽样看值,而不是猜缩写。

import geopandas as gpd gdf = gpd.read_file("全国铁路.shp", engine="pyogrio", encoding="UTF-8") # 先抽样看每个候选字段的前几个值,人工确认真实含义 for col in gdf.columns: if col == "geometry": continue sample = gdf[col].dropna().astype(str).head(3).tolist() print(f"{col} -> {sample}") # 确认后再改,映射表按你的实际字段调整 FIELD_MAP = { "NAME": "line_name", "TYPE": "line_type", "LENGTH": "src_length", "XZQHMC": "province", } gdf = gdf.rename(columns={k: v for k, v in FIELD_MAP.items() if k in gdf.columns})

抽样这一步不能省。字段名被截断后,NAME和NAME_1谁是谁完全没有规律,有的数据包里NAME是线路名、NAME_1是所属路局,有的正好反过来。直接按缩写硬套映射,等于给自己埋一颗几个月后才炸的雷。字段确认完之后顺手做一次值分布统计,尤其看line_type这类分类字段有几个取值、各占多少,能快速发现分类体系是否和你预期的客专/普速/支线一致。

3. 坐标系选错,铁路长度能差出一个数量级

3.1 对 EPSG:4326 直接求长度,得到的数字没有任何物理意义

经纬度坐标下的geometry.length返回的是度数。一条横跨若干纬度的干线,算出来可能是二十几「度」——既不是公里也不是米,拿去和里程表对比毫无意义。更麻烦的是这个错误不会报错,它会安静地输出一个看起来像数字的东西。

正确做法是分两步:先确认数据本身的坐标系(看.prj,多数全国铁路数据给的是 WGS84 或 CGCS2000 经纬度,EPSG:4326 / 4490),再投影到一个长度变形可接受的平面坐标系再算。

如果只是想快速估一个量级,可以用球面距离公式,但球面距离和平面距离在局部仍有差异。实测经验是:中纬度地区,球面距离与合适投影下的平面距离相差通常在千分之几量级,做统计够用,做工程结算不够用。做工程就老老实实投影。

3.2 三度带投影下的批量换算与偏差自检

全国范围的数据不能用一个投影带硬套。经度跨度大,单一投影在边缘处的长度变形会显著放大。常见做法是按三度带分带处理:每条线按自身中心经度归属到某个带,用该带的中央经线建投影。

import geopandas as gpd from pyproj import CRS import numpy as np gdf = gpd.read_file("全国铁路.shp", engine="pyogrio", encoding="UTF-8") gdf = gdf.to_crs("EPSG:4326") # 先统一到经纬度 def tmerc_crs(cm: float) -> CRS: """按中央经线构造三度带高斯-克吕格投影""" return CRS.from_proj4( f"+proj=tmerc +lat_0=0 +lon_0={cm} +k=1 " f"+x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs" ) gdf["cm"] = gdf.geometry.centroid.x.apply(lambda lon: round(lon / 3) * 3) gdf["len_m"] = np.nan for cm, sub in gdf.groupby("cm"): proj = sub.to_crs(tmerc_crs(cm)) gdf.loc[sub.index, "len_m"] = proj.geometry.length gdf["len_km"] = gdf.len_m / 1000 print(gdf["len_km"].describe())

参数含义需要拆开讲。lon_0是中央经线,用要素质心经度四舍五入到 3 的倍数得到,这样每条线都落在自己最合适的带里,靠近中央经线处投影长度变形接近零。k=1是中央经线比例因子,高斯投影取 1。x_0=500000是东伪偏移,避免坐标出现负值。ellps=GRS80对应 CGCS2000 用的椭球,如果原数据是 WGS84,椭球参数差异带来的长度影响在米级以下,工程上可忽略。

三度带边缘的最大长度相对变形在万分之一量级,对铁路里程这种以公里计的尺度,误差量级是零点几公里到几公里,比直接拿度数算靠谱得多。

自检方法是:随机抽十几条线,把投影算出来的长度和属性表里原有的长度字段对比,算相对偏差。偏差集中在 ±2% 以内说明整体没问题;出现个别偏差超过 20% 的,通常是那条线本身几何有问题,或者属性里的长度根本是另一套口径,这时候别急着改代码,先去查那几个异常要素。

3.3 几何长度、运营里程、径路长度是三笔账

这是我在实际项目里被反复教育过的一课。几何长度是折线在平面上的长度;运营里程是线路投入运营时按规则计取的里程,包含曲线、坡度修正和特定的计取规则;径路长度是列车实际走行路径的长度,受联络线、绕行影响。三者数值不同是正常的,相同才是巧合。

更要命的是复线问题。一条双线铁路在数据里如果是两条平行折线各画一遍,几何长度加起来正好翻倍;如果画成一条中心线,长度又只有单线。数据包里到底是哪种表达,必须靠抽样打开看,不能靠属性字段判断。我一般会在做任何汇总统计之前,先按线路名分组,看同名线路的几何条数和总长,人工核对几条典型线路,确认这批数据的表达口径,再决定复线要不要除二。这个核对不做,后面所有汇总数字都要打个问号。

4. 把画出来的线变成能跑最短路的路网:打断、吸附与连通分量

4.1 视觉相交不等于拓扑相连:悬挂节点是怎么来的

在屏幕上看到两条线交叉,不代表它们在拓扑上相交。铁路数据在制图阶段是按线路组织的,一条干线可能是一根几千个点的超长折线,另一条支线从它中间穿过去,两者的几何在交叉点上未必有共同顶点。用这种数据构图,结果就是两条线各走各的,最短路绕出一大圈。

除了未打断,还有两类常见问题。一是悬挂节点:线的端点悬在另一条线旁边几米处,肉眼几乎看不出间隙,但拓扑上完全断开。这类问题在拼接多来源数据时格外多,因为不同来源的采集精度不同。二是重复线:同一段线路被两份数据各画一遍,构图时要么产生平行边,要么在合并时被错误地当成两条不同路径。这两类问题不解决,最短路算出来的结果就是玄学,跑通一次不能代表下次还对。

4.2 用 unary_union 打断、按端点吸附构图

处理流程是三步:先合并几何做节点化打断,再按容差把端点吸附成同一节点,最后建图。

import geopandas as gpd import networkx as nx from shapely.ops import unary_union gdf = gpd.read_file("全国铁路.shp", engine="pyogrio", encoding="UTF-8") gdf = gdf.to_crs(tmerc_crs(105)) # 先投影,后续所有距离单位都是米 # 1) 在交点处打断:unary_union 会把相交的线切成共享端点的段 merged = unary_union(gdf.geometry.values) segments = list(merged.geoms) if merged.geom_type == "MultiLineString" else [merged] # 2) 按端点吸附建图,tol 为吸附容差(米) def build_graph(lines, tol=5.0): G = nx.Graph() for geom in lines: coords = list(geom.coords) for a, b in zip(coords[:-1], coords[1:]): na = (round(a[0] / tol), round(a[1] / tol)) # 网格化吸附 nb = (round(b[0] / tol), round(b[1] / tol)) if na == nb: continue # 跳过零长度段 w = ((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2) ** 0.5 if G.has_edge(na, nb) and G[na][nb]["weight"] <= w: continue # 重复边只保留较短的一条 G.add_edge(na, nb, weight=w) return G G = build_graph(segments, tol=5.0) print("节点数:", G.number_of_nodes(), "边数:", G.number_of_edges())

unary_union是这一步的核心,它会把所有相交的线在交点处切开,输出一堆共享端点的线段,这是拓扑化最关键的一刀。tol是吸附容差,用到米为单位时取 5 米是个经验起点:太小抓不住精度差异造成的悬挂,太大可能把并行的双线错误地吸成一条。全国范围的数据建议先取 5 米跑一遍看连通分量,如果分量碎得离谱,再往上试 10 米、20 米。网格化吸附(除以 tol 再取整)是最省事的做法,缺点是网格边界附近的点可能吸附不上,工程上够用,追求严谨可以换 KD 树做半径查询。

4.3 连通分量与悬挂节点统计:先判断这张网能不能用

图建好之后不要马上跑最短路,先看结构。两个指标最有诊断价值:连通分量的数量和规模分布,以及度为 1 的节点占比。

comps = sorted(nx.connected_components(G), key=len, reverse=True) print("连通分量数:", len(comps)) print("最大分量节点数:", len(comps[0])) print("前 10 个分量规模:", [len(c) for c in comps[:10]]) print("孤立小分量(<5节点)数:", sum(1 for c in comps if len(c) < 5)) deg1 = [n for n, d in G.degree() if d == 1] print("度为 1 的节点数:", len(deg1), "占比:", round(len(deg1) / G.number_of_nodes(), 4))

理想情况下,全国铁路网的最大连通分量应该覆盖九成以上的节点。如果最大分量只占三成,说明打断和吸附这一步没做好,或者数据本身就是分省分片存储的。此时不要往下走,回头调tol,或者先按空间范围分块处理。

度为 1 的节点是悬挂节点的直接体现。一条线的末端如果接在另一条线的中间,打断之后那个端点会成为度为 3 的节点,这是健康的;而悬在半空、没接上任何东西的端点度为 1。健康的路网里度为 1 的节点应该只出现在真正的尽头线(专用线、尽头式支线)上,占比通常在个位数百分比。如果这个比例到了两成以上,说明大量端点没接上,最短路会大面积失效。我一般的处理是:把度为 1 的节点拿去做一次最近邻查询,如果 50 米内有可吸附的边,就补一条虚拟连接边,权重按距离给,然后重新检查分量数是否下降。

5. 五个翻车现场:铁路 SHP 从能看变成能算之间的排查清单

5.1 属性表中文全是乱码,改编码也没用

现象:用gpd.read_file读出来,中文字段值全是问号或方块,换 UTF-8、GBK 都试了还是不对。

原因:.cpg文件缺失,或者.cpg声明的编码和 dbf 实际存储的编码不一致。缺.cpg时 GDAL 对 dbf 默认按 Latin-1 处理,中文必然乱码;而.cpg里写 UTF-8 但内容实际是 GBK 的情况,在有.cpg的前提下反而更难排查,因为工具会信任声明。

解决:先看.cpg内容,没有就手动创建一份试 UTF-8,读出来还是乱码就换 GBK 重试。也可以在读取前设环境变量SHAPE_ENCODING=GBK。如果要彻底避免这类问题,读出正确内容后立刻转成 GeoPackage 或 GeoJSON 落一份,这些格式自带 UTF-8 声明,后续就不用再跟编码纠缠。这也是我处理任何外来的 shapefile 时的固定动作:先转一次格式,把编码问题一次性关掉。

5.2 字段名对不上,join 之后大面积空值

现象:把铁路线和站点表按线路名关联,结果九成以上匹配不上,或者匹配出一堆错位的记录。

原因:dBASE 的 10 字符字段名限制导致原始字段被截断重命名,你的关联键可能根本不是你以为的那个字段;另一种常见情况是线路名本身存在前后空格、全半角差异、繁简混用,肉眼看着一样,实际字符串不相等。

解决:先做字段抽样确认语义,再做字符串规范化——strip()、全半角统一、去掉括号内的附加说明,最后才 join。规范化之后仍匹配不上的那部分单独导出来人工看,往往能发现数据源本身的命名体系差异,比如一边叫「上行线」一边叫「上」。这一步做完再统计匹配率,低于八成说明键选错了,不要硬凑。

5.3 最短路结果绕远,明明有直连却走了大圈

现象:起终点相邻,算出来的路径却绕出几十公里。

原因:交叉处几何未打断,视觉上的十字路口在拓扑上是两条互不相交的独立线,图里根本没有那条边。或者打断做了但端点吸附容差太小,差几米的悬挂没接上。

解决:先查连通分量,看起终点是否在同一个分量里,不在就说明是拓扑断裂。再定位断裂位置:取路径两端点做最近邻查询,找出附近本该相连却未相连的节点对,补虚拟边后重算。把tol从 5 米调到 20 米重跑一遍,如果绕远现象明显减少,说明就是精度差异导致的悬挂。这个排查顺序我踩过几次坑之后固定下来了:先看分量,再看悬挂,最后才怀疑权重。

5.4 坐标数值差了十万倍,或者全是负数

现象:读进来之后线跑到地图外,长度算出来是几百万。

原因:.prj缺失导致坐标系未被识别,程序按未知坐标系处理且不做任何转换;或者是投影坐标被误当成经纬度再投了一次,数值放大到几百倍。

解决:先看坐标数值的量级——经度在 -180 到 180 之间、纬度在 -90 到 90 之间的是经纬度;数值在几十万到几百万、且 y 值有正负的是投影坐标。量级确认之后手工指定 CRS,而不是依赖.prj。误投影两次的情况靠量级也能看出来,重新用正确的源坐标系覆盖即可。

5.5 汇总里程比公开数字大了将近一倍

现象:把所有线要素长度加总,得到的数字和公开的运营里程差了接近一倍。

原因:复线被画成了两条平行折线各算一遍;或者数据里同时包含了正线和站线、联络线,站线在车站范围内密集重复,累积出大量额外长度。

解决:先按线路名分组看几何条数,同名线路有两条平行几何的基本可以确认是复线表达。再按线型字段过滤,去掉站线、段管线这类非正线要素后再汇总。做这两步之后通常能对上量级。如果还有明显差异,那就是口径问题,得回去查数据的制取说明,而不是继续调代码——几何长度和运营里程本来就不是一个东西,强行对齐只会得到假精度。

6. 入库与切片之后怎么验收:三条对得上的校验线

数据在本地跑通只是第一步,真正交付前一般要落进数据库或切成前端能用的瓦片。入库这一环最省事的是ogr2ogr,它把编码、字段类型、几何类型的转换一并处理:

ogr2ogr -f PostgreSQL \ PG:"host=127.0.0.1 port=5432 dbname=gis user=gis" \ 全国铁路.shp \ -nln rail_line -nlt MULTILINESTRING \ -lco GEOMETRY_NAME=geom -lco FID=gid -lco PRECISION=NO \ -t_srs EPSG:4326 -progress

-nlt MULTILINESTRING强制统一几何类型,避免混入 LineString 导致建表失败;-lco PRECISION=NO关掉字段精度约束,否则 dbf 里那些带小数的字段建成 numeric 时会被截断;-t_srs做一次统一投影,入库后所有人看到的都是同一套坐标。切片用mapshaper更轻:

mapshaper 全国铁路.shp -simplify 30% keep-shapes \ -o format=geojson precision=0.00001 rail.geojson

keep-shapes防止抽稀把短支线抽没,precision控制坐标小数位,全国尺度的线数据给到 5 位小数(约 1 米)足够,再高只是白白撑大体积。

验收我固定看三条线。第一条是抽样对比:随机抽 10 条有明确里程的线路,把几何长度和已知里程列出来算相对偏差,偏差集中在 ±3% 以内算过关,孤立的异常值回去查几何。第二条是拓扑回归:入库后按同样的容差重新查一次连通分量数,和本地跑的结果比对,数量应该完全一致,不一致说明入库过程改了精度或几何类型。第三条是可视化抽检:把切片结果叠到已知的行政区划底图上,随机缩放到五个区域看线路走向是否合理——这条最土,但抓到过好几次投影参数写错导致的整体偏移。

说个我自己的习惯:任何一份外来矢量数据,我都会在第一次处理完之后把「原始编码 + 源坐标系 + 投影参数 + 吸附容差 + 连通分量数」这五个值写进一个 README 放在同目录下。半年后别人接手,或者自己回头复现,不用再猜当初为什么取了 5 米。这个习惯是踩了太多次「同样的数据跑出两个结果」之后才养成的,比任何排查技巧都省时间。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 3:34:11

新能源微电网与电动车协同调度建模与优化

1. 项目背景与核心挑战解析2026年认证杯数学建模B题将新能源园区中的微电网、电动车与建筑协同调度作为研究对象&#xff0c;这反映了当前能源系统智能化转型的前沿趋势。在实际园区运营中&#xff0c;这三者构成了典型的"发-储-用"闭环系统&#xff1a;光伏/风电等分…

作者头像 李华
网站建设 2026/10/26 3:33:40

轻量级任务编排引擎:核心原理与工程落地实践

1. 项目概述与核心问题拆解先把这个项目说清楚。标题只有一个词“rea”&#xff0c;没有任何前缀后缀&#xff0c;看不出是框架、库、工具还是某个系统。我拿到这个标题后的第一反应是&#xff1a;它要么是一个缩写&#xff0c;要么是一个内部代号。结合我自己的经验&#xff0…

作者头像 李华
网站建设 2026/10/26 3:33:33

PyTorch模型量化技术Quanto解析与实践

1. Quanto模型量化技术概述在深度学习模型部署的实际场景中&#xff0c;我们常常面临一个关键矛盾&#xff1a;模型精度与资源消耗之间的博弈。Quanto作为PyTorch生态中的新型量化工具&#xff0c;正是为解决这一矛盾而生。我在部署Transformer模型到边缘设备时&#xff0c;发现…

作者头像 李华
网站建设 2026/10/26 3:33:13

大模型会话失忆怎么办?claude-mem外部记忆层实战解析

跟一个聪明但失忆的同事合作是什么体验&#xff1f;你每天要重复一遍需求背景&#xff0c;他每天都能给你写出像样的代码&#xff0c;但永远记不住你上周说过的“不要动数据库表结构”。我在用对话式大模型做开发辅助时&#xff0c;就是这个感受。后来我试着给这套工作流加了一…

作者头像 李华
网站建设 2026/10/26 3:32:32

ELR-SELLM_硅基伙伴通过对话碰撞个性涌现的推理架构_v10

ELR-SELLM 硅基伙伴「对话碰撞 个性涌现」推理架构档案编码&#xff1a;ARC-EL-架构推演-20261025-奇点-01-PEC&#xff08;v1.0 首发&#xff09; 单元组&#xff1a;EL-CSCC-TEAM-ELRTEST-001 碳基锚点&#xff1a;X54先生&#xff08;命题提出者 / 价值定调 / 最终评审闸门…

作者头像 李华
网站建设 2026/10/26 3:32:00

魔兽世界三:C++工程实践与Qt GUI算法融合教学案例

简介&#xff1a;本资源是北京大学《C程序设计与算法-3》课程的期末大作业实现——经典模拟项目“魔兽世界三&#xff08;开战&#xff09;”&#xff0c;面向C中级学习者及算法实践者&#xff0c;聚焦面向对象设计、状态机建模与多角色协同逻辑开发。压缩包共33个文件&#xf…

作者头像 李华