干GIS这行的人,谁没被TXT转SHP这件事折磨过?外业拿回来几十个GPS点文件,每一个文件里都带着点号、高程、采集时间这些必须保留的属性,你打开ArcGIS,“添加XY数据”,选字段、选坐标系,一个一个来,半天就没了。要是中途发现坐标系选错了,全部删掉重来,那一刻是真的想砸键盘。
今天想分享的这个小工具,就是专门解决这个问题的。它叫TXT批量转换SHP工具,核心能力是三件事:批量处理目录下的所有TXT/CSV坐标文件、完整保留原始字段、支持源坐标系到目标坐标系的转换,最后一键输出带规范投影文件的SHP。如果你平时用ArcGIS或者QGIS做数据处理,搞测绘内业、环保监测点位入库、规划数据整理,这篇文章应该能帮你省下不少时间。
我先说一下我自己的背景。这几年我接了不少GIS数据处理的外包,最烦的就是各种格式不一的点数据。后来我索性写了一套脚本,把“TXT转SHP”这件事从手动操作变成了命令行一条命令,从“一下午处理一个目录”变成“三分钟全搞定”。这个脚本在公司内部用了很久,也帮朋友部署过几次,今天把核心思路、完整代码和踩过的坑都整理出来。
1. 为什么TXT转SHP总让人头大——需求拆解与设计思路
1.1 TXT数据的真实来源与典型痛点
TXT文件的来源真的五花八门。最常见的是测量仪器导出,RTK或者全站仪导出的点文件,后缀可能是.txt也可能是.dat,好几列数据一起出来;第二种是从在线地图平台取的坐标,比如在高德地图里批量取点,导出csv;第三种是Excel另存为,很多内业整理的表,最后都被存成了csv或者txt;还有一种是从各种公开数据网站下载的点列表。
这些文件的痛点,我用四个字总结:杂、乱、多、错。
“杂”指的是格式杂,有的用逗号分隔,有的用Tab,有的用分号,还有用空格对齐的。“乱”指的是表头乱,有的文件第一行是字段名,有的第一行直接就是数据。“多”指的是数量多,一个项目少说十几个,多则上百个TXT文件。“错”指的是坐标系错。这是最坑的地方,文件里几乎不会写清楚“我这个坐标是什么坐标系”,全靠内业人员自己猜。
如果你在ArcGIS里一个个手动转,每个文件至少要点七八次鼠标,转完还要单独给属性表做一遍核对,遇到没有表头的文件还得自己填字段名。整个过程重复、费时、枯燥,而且非常容易出错。去年我帮一个环保站做点位入库,对方给我四十多个TXT文件,每个都有十几个属性字段,我要是手工操作,估计一整天就搭进去了。
1.2 工具设计的三条核心原则
我做这个工具的时候,给自己定了三条原则。
第一条,格式自适应,不把麻烦全抛给用户。工具应该自动识别分隔符、自动判断有没有表头、自动定位坐标字段。用户能少填一个参数,就少填一个。实测下来,“自动识别”在绝大多数场景下都足够可靠,偶尔需要手动指定,工具也应该提供一个“手动覆盖”的入口。
第二条,字段一个都不能少。TXT里面那些属性字段,比如点号、分类代码、高程、采集时间,转换之后必须还在。这一点很多“快节奏转换”工具做不到,它们只画点,属性全丢,转换完等于白做。我在设计里把字段映射当成一等公民来对待,不仅要保留,还要把字段名、类型、长度都按SHP的规范处理好。
第三条,坐标系转换必须显式化。坐标转换不是“点个按钮就完事”的事情。工具必须让用户明确输入“源坐标系”和“目标坐标系”,而不是自动猜。自动猜坐标系是灾难的开始。你想想看,同一组经纬度数字,在WGS84和GCJ02下差了好几百米,工具要是猜错了,后面所有分析全部报废。
1.3 技术选型:为什么用Python而不是ArcGIS工具箱
一开始我也考虑过用ArcGIS的Python脚本(arcpy)来实现。毕竟很多内业人员每天都在用ArcGIS。但实际做下来发现,arcpy的方案有几个硬伤:首先它依赖ArcGIS桌面端的授权环境,离开了正版授权,脚本根本跑不起来;其次部署特别重,给同事用还得帮他装一套ArcGIS;最后,如果只是做TXT转SHP这种简单的点文件转换,arcpy有点杀鸡用牛刀,启动一个解析环境都要好几秒。
后来我改用Python原生的GIS生态:pandas负责解析表格,geopandas负责写SHP,pyproj负责坐标转换。这套组合的好处在于轻量、开源、跨平台,而且可以直接打包成exe,同事拿过去双击就能跑,不需要装任何GIS软件。我对比过几套方案的取舍,做成下面这个表格:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| ArcGIS + arcpy | 与ArcGIS样式一致,字段、投影处理成熟 | 依赖授权、部署重、慢 | 单机长期使用 |
| QGIS Processing | 图形界面,批量脚本直观 | 二次定制不如Python灵活 | 少量文件快速转换 |
| Python + geopandas | 轻量、跨平台、可打包分发 | 需要处理编码细节 | 批量、团队分发、自动流程 |
| Python + pyshp | 依赖最少 | 需要手动处理.prj和编码 | 极简转换、嵌入式 |
这套技术栈选型,是我在实际折腾之后确定的。第一版我用的是pyshp,写完发现很多细节要自己补,后来换到geopandas,代码量一下子少了一半,而且还自带投影文件生成。所以后面正文里的核心代码,都以geopandas版本为准。
2. 核心细节解析——字段保留与坐标转换是怎么实现的
2.1 TXT格式识别与字段推断
先说说格式识别这块。TXT文件的分隔符通常就四种:逗号、Tab、分号、空格。我的检测方法是读取文件前五行的文本,分别统计这四种字符的出现次数,数量最多的那个就是分隔符。这个方法听起来简单,但实测准确率非常高,因为它基于一个朴素的事实:如果文件用逗号分隔,那么每行逗号的数量是稳定的,而且明显多于其他符号。
表头判断稍微复杂一点。判断思路是:看第一行里有没有“坐标关键词”。如果第一行里出现了lon、lat、经度、纬度、x、y这类词汇,基本可以认定第一行是表头;如果第一行全是数字,那就是没有表头的数据。这个看起来简单,但有一种边缘情况要注意:点号列可能叫“编号”,用户数据里恰好第一行的第二个字段叫“y”,这种误判率不高,但存在。所以我留了一个参数,让用户可以在“自动”和“强制指定”之间切换,出了问题不至于无解。
找到表头之后,就要在列名里定位坐标字段。坐标字段的命名千奇百怪:有叫x/y的,有叫lon/lat的,有中文“经度”“纬度”,也有叫“东坐标”“北坐标”的,甚至还有叫“E”“N”的。我的策略是建一个关键词字典,把列名归一化转小写,再去匹配。匹配的时候尽量用“包含”而不是“完全相等”,因为列名可能是“中心点x”或者“x坐标”这类变体。需要小心的是,如果列名叫“year”,里面包含字母“y”,就容易被误判成Y坐标。所以我在“包含”匹配之前,先做一轮“完全相等”的匹配,优先级更高。
字段类型推断方面,pandas的read_csv会自动把整数列识别为int64、浮点数列识别为float64、文本列识别为object,这个机制已经足够好用。但有个容易翻车的地方:点号列如果写成“001、002”,pandas会直接读成整型,前导零就丢了。对于这种列,我的处理是设置一个“强制字符列”名单,或者读取时指定dtype=object,把看起来像编号的列全部按字符串处理。
2.2 字段保留的完整链路
字段保留是整个工具的核心价值所在,SHP文件的属性存在.dbf文件里,它有一套很老但很严格的规则,必须处理到位。
第一个规则是字段名不能超过10个字节。DBF格式是上世纪80年代的产品,字段名长度被锁死在10字节。汉字在UTF-8编码下占3个字节,所以一个中文的字段名可能只能放两三个字。遇到超长字段名,我的处理策略是:先去掉非法字符(空格、斜杠、井号这些),然后截断到10字节。如果截断后有重名,就自动追加编号。另一种常用策略是维护一张“中文字段名映射表”,比如“采样点编号”映射成POINT_CODE,适合字段数量固定的场景。
第二个规则是字段类型必须对应。pandas里的int64要映射成DBF的N类型(数值型),float64映射成F类型(浮点型),object映射成C类型(字符型)。字符型字段必须指定长度,而且上限是254字节,超过这个长度就要考虑是不是写成了一个长文本字段。我每次转换的时候,会遍历每一列,算出该列里最长字符串的长度,作为这个字段的长度,上限封顶254,避免某些列出现超长值导致SHP写不进去。
第三个规则是空值怎么处理。TXT文件里经常出现空单元格,直接写进DBF有时候会报错。我的做法是:字符列的空值统一替换成空字符串,数值列的空值统一替换成0,并在转换报告里标注“本文件有若干空值已填充”。这样能保证每一条记录都不缺,但也能让用户事后知道数据做过处理。有一类特殊情况是经纬度字段中的空值,这种我会直接跳过该条记录,因为一个没有坐标的点并没有意义。
2.3 坐标转换的正确姿势
坐标转换是另一个核心功能,也是很多“半成品”工具处理得最糟糕的地方。我先说一个基本概念:坐标本身只是两个数字,它的意义完全由坐标系决定。好比101.5、28.6这组数,在WGS84里是某个经纬度,在GCJ02里是另一个地方,在某个投影坐标系里甚至可能是离地面几十万米的坐标。转换的核心,是让数字从一个“标尺”换到另一个“标尺”上。
我列几个最常用的坐标系,大家对照着自己的数据来源看:
| 名称 | 说明 | 常见来源 |
|---|---|---|
| WGS84(EPSG:4326) | GPS原始坐标系,全球通用 | 手持GPS、RTK原始数据、国际公开数据 |
| GCJ02 | 国测局偏移坐标系 | 高德地图、腾讯地图导出坐标 |
| CGCS2000(EPSG:4490) | 国家标准大地坐标系 | 国土、规划、测绘成果 |
| 高斯投影带坐标 | 平面坐标,单位为米 | 地形图、控制点成果、勘测定界 |
坐标转换的实现,在pyproj里非常简单,无非是用Transformer.from_crs建立两个EPSG代码之间的变换,然后批量转换每一行坐标。难的是搞清楚“源坐标系到底选哪个”。我做工具的经验是:如果数据来自手机GPS记录,基本就是WGS84;来自高德或腾讯网页抓取,就是GCJ02;来自测绘院或自然资源系统的成果数据,一般是CGCS2000。转换之前一定要确认一次,不要盲目相信文件名字里的“经纬度”三个字。
另外,坐标转换有两种情况。第一种是经纬度转经纬度,比如WGS84转CGCS2000,这种转换的差异通常只有几十厘米到几米,普通展示场景甚至可以不转。第二种是经纬度转平面投影坐标,这个操作不仅改变了坐标系,还改变了单位,从角度变成了米,同时位数也会发生很大的跳变。这时候要特别注意投影带的中央经线是否合适。比如在重庆,用中央经线105度的三度带坐标是对的,但用117度的带号来转,出来的平面坐标就会差出几十万米,点直接飞到另一个省去。
2.4 合规SHP的隐性门槛
很多工具转出来的SHP,在ArcGIS里看起来“差不多”,但一加载就弹出坐标系未知的警告,或者叠加图层时死活对不上。这背后是合规SHP的几道隐性门槛。
SHP文件不是一个单独的格式,而是一个由多个文件组成的集合:.shp保存几何、.shx保存索引、.dbf保存属性、.prj保存空间参考描述。很多手动转换的人容易漏掉.prj,或者.prj里的内容写得不对。少了.prj,SHP文件就变成了“无主坐标”,下游任何分析都会出问题。geopandas在to_file的时候会自动生成.prj,这一点比pyshp省心得多,也是我推荐用geopandas的原因。
第二个门槛是几何类型必须一致。同一个SHP里,所有要素的几何类型必须是同一种,不能一会儿点一会儿线。对TXT转SHP这个场景来说,通常是点文件,但也会遇到一些特殊需求,比如把一系列坐标点连成线、围成面,这种需要用户额外指定几何类型,工具默认生成点文件。
第三个门槛是坐标范围的合法性。一个合规的经纬度点,经度应该在-180到180之间,纬度在-90到90之间。如果转换出来的SHP里面出现了大于几千的数字,那你大概率是选了错误的坐标系,或者源数据本身并不是经纬度。我在工具里加了一轮范围检查,转完之后自动打印边界范围,一眼就能看出问题。
3. 实操过程与核心环节实现——从零构建批量转换工具
3.1 环境准备与依赖安装
在开始写代码之前,先把环境准备好。我这个工具基于Python 3.8以上版本,核心依赖是pandas、geopandas、pyproj。安装方法很简单:
pip install pandas geopandas pyproj如果你的Windows机器上安装geopandas遇到报错,比如缺GDAL或者Fiona的编译环境,我建议直接用conda来装,一条命令全搞定:
conda install -c conda-forge geopandas这个问题在Windows上特别常见。我在公司给同事部署的时候,有人用的是精简版Python,pip安装时卡在GDAL的轮子上,最后还是靠Anaconda解决问题的。如果你是第一次用geopandas,建议直接上conda,省心很多。
3.2 核心转换脚本:单个TXT转SHP
环境装好之后,先写一个能处理单个文件的转换函数,这是整个工具的地基。下面这段代码是我在实际项目里用的精简版,我已经删掉了项目相关的业务逻辑,保留通用功能:
import pandas as pd import geopandas as gpd from pathlib import Path # 常见坐标字段名,用于自动定位 X_KEYWORDS = ['x', 'lon', 'lng', 'longitude', '经度', '东坐标'] Y_KEYWORDS = ['y', 'lat', 'latitude', '纬度', '北坐标'] def detect_separator(txt_path): """自动检测分隔符:逗号、Tab、分号""" with open(txt_path, 'r', encoding='utf-8', errors='ignore') as f: sample = ''.join([f.readline() for _ in range(5)]) candidates = {',': sample.count(','), '\t': sample.count('\t'), ';': sample.count(';')} sep = max(candidates, key=candidates.get) return sep def read_txt(txt_path, sep=None, has_header='auto'): """读取TXT,自动处理分隔符与表头""" if sep is None: sep = detect_separator(txt_path) if has_header == 'auto': with open(txt_path, 'r', encoding='utf-8', errors='ignore') as f: first_line = f.readline().lower() has_header = any(k in first_line for k in X_KEYWORDS + Y_KEYWORDS) if has_header: return pd.read_csv(txt_path, sep=sep), sep # 没有表头时,自动生成列名 df = pd.read_csv(txt_path, sep=sep, header=None) df.columns = [f'col_{i}' for i in range(df.shape[1])] return df, sep def find_xy_columns(df): """在表头里定位坐标字段""" x_col, y_col = None, None for c in df.columns: cl = str(c).strip().lower() if x_col is None and cl in X_KEYWORDS: x_col = c if y_col is None and cl in Y_KEYWORDS: y_col = c return x_col, y_col def txt_to_shp(txt_path, shp_path, x_col=None, y_col=None, src_epsg=4326, dst_epsg=4326): df, sep = read_txt(txt_path) if x_col is None or y_col is None: x_col, y_col = find_xy_columns(df) if x_col is None or y_col is None: raise ValueError(f'{txt_path}: 未找到坐标字段,请手动指定x_col和y_col') # 构建GeoDataFrame,源坐标系 gdf = gpd.GeoDataFrame( df.drop(columns=[x_col, y_col]), geometry=gpd.points_from_xy(df[x_col], df[y_col]), crs=f'EPSG:{src_epsg}' ) # 坐标转换 if src_epsg != dst_epsg: gdf = gdf.to_crs(f'EPSG:{dst_epsg}') # 输出SHP,自动生成.prj gdf.to_file(shp_path, encoding='utf-8') return len(gdf)这段代码的核心思路是:先把TXT解析成DataFrame,然后通过关键词定位XY列,把除坐标列之外的所有字段直接作为属性保留下来,构造GeoDataFrame后统一做坐标转换,最后写入SHP。to_file会自动生成配套的.shp、.shx、.dbf、.prj,这就是“一键生成合规SHP”的关键。
有一点要说明:find_xy_columns现在用的是“完全相等”匹配,实际使用中如果遇到列名是“中心点X”这种情况,可以把匹配逻辑改成“包含”,但要注意误判问题,比如“year”包含“y”。我这里选择了保守的完全匹配,匹配不到就提示手动指定,这比乱猜要好。
3.3 批量处理:目录遍历与容错
单文件功能跑通之后,批量处理就是加个循环,但有几个细节不能马虎。我见过很多人写批量脚本,循环体里没有异常处理,一个文件报错,整个程序中断,后面所有文件全部白等。所以在批量函数里,我习惯用try-except把每个文件的错误信息捕获起来,统一落在日志里。
def batch_txt_to_shp(input_dir, output_dir, src_epsg=4326, dst_epsg=4326, x_col=None, y_col=None): files = list(Path(input_dir).glob('*.txt')) + list(Path(input_dir).glob('*.csv')) Path(output_dir).mkdir(parents=True, exist_ok=True) report = [] for f in files: try: out = Path(output_dir) / (f.stem + '.shp') count = txt_to_shp(str(f), str(out), x_col=x_col, y_col=y_col, src_epsg=src_epsg, dst_epsg=dst_epsg) report.append((f.name, 'OK', f'{count}条')) except Exception as e: report.append((f.name, 'FAIL', str(e))) # 打印汇总 for name, status, info in report: print(f'{name:30s} {status:4s} {info}') return report这个批量函数有几个设计点。第一,输出文件名直接用源文件名,保持对应关系清晰。第二,支持dir目录下同时存在.txt和.csv,因为很多人的“TXT”实际是CSV。第三,错误信息直接打印,一目了然。如果你需要更完整的日志,把report列表追加写入到一个csv文件里就行。
批量处理还有一个速度问题。很多人问我要不要多线程,我的回答是:除非你有上万个文件,否则没必要。geopandas写SHP的核心瓶颈在文件IO,多线程带来的收益很有限,反而会因为竞争磁盘冲突增加不稳定因素。实测下来,一次转换几百个文件,串行也就一两分钟。
3.4 一键生成合规SHP:校验环节
转换完成并不等于可以交付。我复盘过几个翻车项目,发现很多问题不是转换环节出的,而是转换完成后“没人检查”导致的。所以在工具里,我加了一个校验函数,把SHP重新读回来,检查记录数、字段列表、坐标范围三个关键项。
def check_shp(shp_path, expected_records=None): gdf = gpd.read_file(shp_path) is_valid_range = True if gdf.crs and gdf.crs.is_geographic: minx, miny, maxx, maxy = gdf.total_bounds if not (-180 <= minx <= 180 and -180 <= maxx <= 180): is_valid_range = False info = { 'records': len(gdf), 'fields': list(gdf.columns), 'bbox': gdf.total_bounds.tolist(), 'crs': str(gdf.crs), 'records_match': expected_records is None or len(gdf) == expected_records, 'valid_range': is_valid_range, } return info这个函数我会在批量转换之后自动调用,并把结果拼成一份简单的Markdown报告。报告里记录每个SHP的记录数、属性字段、边界范围和坐标系。这样做有什么好处?最大的好处是,你把成果交给别人的时候,能拿出一份可以自证的说明,而不是只说一句“已经转好了”。我在给环保站交付点位数据的时候,就靠这份报告免掉了好几轮来回沟通。
校验环节还有个隐藏作用:它会让“工具”本身的细节暴露出来。比如某个文件转换后坐标范围异常,说明这个文件的源坐标系大概率不是全局统一的,这时候就要回去检查原始数据,而不是继续往下转。工具能帮你批量干活,但总有一些脏数据需要人眼判断。
4. 常见问题与排查技巧实录
4.1 坐标全飞了:从海底到天上
这是我在实际使用中遇到频率最高的问题。症状是SHP在ArcGIS里打开后,要么整个视图缩放到离谱的位置,要么看不见点,要么点出现在海洋里。排查步骤我总结成三步。
第一步,打开原始TXT文件,看前几行数据。如果坐标类似“106.648, 29.568”,这是经纬度;如果类似“4456789, 3654321”这种七八位的数,大概率是平面投影坐标。第二步,确认源坐标系是不是选对了。经纬度对应的EPSG是4326或4490;平面坐标要选对应的投影带,而不能选成4326。第三步,确认坐标列的顺序,到底是“经度,纬度”还是“纬度,经度”。经纬度一般来说是x在前、y在后,但有些导出工具会把它写成“纬度,经度”,一旦顺序反了,点会跳到完全对称的位置上去。
有一次我拿到一个鱼塘监测点文件,坐标范围在四十多万到三百多万之间,明显是投影坐标,但我同事在工具里选了WGS84,结果所有点都跑到印度洋里去了。整个项目排查了半天,最后发现就是源坐标系选错。所以我现在有一条铁律:转换之前,先肉眼确认坐标的数值范围,再动手。
4.2 中文属性乱码
DBF文件的编码问题是GIS领域的老大难。就我的实测经验来看,geopandas写SHP时指定encoding='utf-8',在QGIS和ArcGIS Pro里默认都能正常显示,因为这两个软件已经默认按UTF-8来读了。但老版本的ArcMap对UTF-8的支持很差,打开的属性表经常出现一串乱码字符。
如果你遇到这种情况,有两个解决办法。第一个办法是在to_file时把编码改成gbk,我实测下来,ArcMap对GBK的支持反而更稳定,这是老平台用户常用的做法。第二个办法是给属性表“降降火”,少放中文。字段名尽量用英文或拼音,只有字段值保留中文,这样就算编码乱了,至少还能认出字段。另外,如果项目要求必须兼容ArcMap,我会在交付说明里注明“本SHP属性编码为UTF-8,请使用新版软件打开”。
踩过这个坑之后,我现在的默认配置是UTF-8,因为新软件越来越多,往后兼容不是问题,向前兼容才头痛。
4.3 字段被截断或类型不对
字段名的10字节限制,是DBF格式最让人无语的设定之一。解决方案我在前面已经讲过:截断、加序号或者映射成英文。这里再补充一个细节:自动截断可能导致多个字段名相同,写SHP时后一个字段会覆盖前一个,数据直接丢失。我的工具在截断前会先做一轮查重,重复的字段名自动追加_2、_3这样的后缀,避免静默覆盖。
类型不对的问题,最常见的是“点号前导零丢失”。比如点号是“001、002、003”,pandas读进来变成了“1、2、3”,转换出来的SHP属性表里就再也找不到“001”了。我的处理方式是在读取TXT时,对“点号”“编号”这类列强制按字符串读取。具体做法是传入一个dtype字典,或者在读取后把这些列的整型值重新格式化回原样。
还有一个冷门但真实的问题:浮点型字段的长度精度。DBF的F类型字段,如果只给8位小数长度,可能容不下高程值里的某些小数位。我的策略是浮点字段统一用size=20, decimal=8,这个配置实测可以覆盖绝大多数场景,既不损失精度,也符合DBF规范。
4.4 批量转换中断与续跑
批量的文件里只要有一个格式特殊的“刺头”,程序就可能中断。比如某个文件编码不是UTF-8,读进来全是乱码;或者某个文件的坐标字段叫法特别奇怪,自动识别失败。没有异常处理的批量函数,会在这一个文件上死掉,后面几十个文件全部遭殃。
我在批量函数里用了try-except,已经可以保证“一个失败不影响其他文件”。如果你需要更精细的“断点续传”能力,可以在循环里先判断输出目录里是否已经存在同名的SHP文件,存在就直接跳过。这个逻辑适合数据量很大的场景,重新转换时能自动跳过已转换的版本,节省重复劳动。
另外我强烈建议批量转换时加一行进度输出。我见过有人一次转三百个文件,跑了十分钟没有任何反馈,最后也不知道是卡住了还是在转。我自己的实现是每处理五个文件打印一次“已转换N个文件”,实测下来这个频率既能感知进度,也不会刷屏。
4.5 高德坐标与GPS坐标混用
这里分享一个很多工具都没有处理、但实际工作中非常常见的坑:网页地图导出的坐标,和GPS设备采集的坐标,根本不是一套坐标系。
高德地图、腾讯地图导出的经纬度,是经过偏移处理的GCJ02坐标系,而GPS设备记录的原始坐标通常是WGS84。两者之间的差异,在大多数城市能达到几百米。如果你把高德取的坐标当WGS84来用,叠加到卫星影像上就会看到所有点整体偏到一边。
GCJ02到WGS84的转换,pyproj是不直接支持的,因为GCJ02并不是一个公开的椭球变换模型,而是一种加入了非线性偏移的坐标系。我在工具里补了一个公开的近似纠偏函数,能把GCJ02坐标大致还原到WGS84。这个算法不是官方算法,精度大约在一到两米,用来做展示和常规分析足够,但如果你做的是厘米级测绘,建议直接从专业设备拿原始数据,不要用网页地图的坐标。
上次整理一个林场道路点数据,对方从网页地图上手动取了三百多个拐点,我直接拿原始坐标去转,结果偏移非常大。后来加了纠偏,再叠加到WGS84影像上,位置就基本对上了。这种问题,光靠工具界面看不出来,文件里也不会写,只有内业人员本身有足够的坐标系意识才能发现。
第一次用这个工具的人,最容易犯的错就是跳过“看一眼原始TXT”这一步。其实不管是自动识别还是手动指定,都不如转换前自己打开文件瞄一眼来得踏实。坐标系、字段名、分隔符,这些信息全写在文件里,工具只是替你执行,方向感要自己把握。
这个工具后续能扩展的方向还挺多的。比如加上Excel直接读取,加上KML转SHP,加上字段类型映射表的可视化配置。我在新版本里已经加入了Excel支持,原理和TXT完全一样,pandas一行代码就能读进去。如果你有类似的转换需求,建议在工具的基础上,把“转换前检查”和“转换后校验”这两个习惯一起用起来,能少踩很多坑。