一、功能介绍
TXTToFeature:将带坐标点的TXT文件批量转矢量
TXT格式如下:
[属性描述]
坐标系=2000国家大地坐标系
几度分带=3
投影类型=高斯克吕格
计量单位=米
带号=****
精度=****
转换参数=,,,,,,
[地块坐标]
***,****,****/***/,xxxx,,,,,@
J01,1,2971685.152000,38993024.791000
J02,1,2971696.601000,38993013.240000
J03,1,2971695.439000,38992748.939000
J04,1,2971685.152000,38993024.791000
二、实现代码
# -*- coding: cp936 -*-
import arcpy
import os
import sys
import re
import codecs
class TXTToFeatureConverter:
"""TXT转矢量要素转换器"""
def __init__(self):
"""初始化"""
# 设置环境
arcpy.env.overwriteOutput = True
def read_txt_file(self, filepath):
"""读取TXT文件,返回文件内容"""
try:
# 尝试不同的编码读取
encodings = ['gbk', 'gb2312', 'utf-8', 'utf-8-sig', 'cp936']
for encoding in encodings:
try:
with codecs.open(filepath, 'r', encoding=encoding) as f:
content = f.read()
return content
except UnicodeDecodeError:
continue
except Exception as e:
arcpy.AddWarning(u"读取文件失败 {}: {}".format(os.path.basename(filepath), str(e)))
continue
# 如果所有编码都失败,尝试二进制读取
with open(filepath, 'rb') as f:
raw_data = f.read()
try:
return raw_data.decode('gbk', errors='ignore')
except:
return raw_data.decode('utf-8', errors='ignore')
except Exception as e:
arcpy.AddWarning(u"无法读取文件 {}: {}".format(os.path.basename(filepath), str(e)))
return None
def parse_txt_content(self, content, filename):
"""解析TXT内容,提取地块数据"""
plots = [] # 存储所有地块数据
if not content:
return plots
lines = content.splitlines()
in_coord_section = False
current_attrs = {}
current_points = []
current_plot_started = False
for line in lines:
line = line.strip()
# 检测地块坐标部分开始
if line == "[地块坐标]":
in_coord_section = True
arcpy.AddMessage(u" 找到'地块坐标'标记")
continue
if not in_coord_section:
continue
# 处理属性行(地块起始行) - 示例: 135,5.5985,DDE2023020,燕子窝货运码头地块,,G50G024016,工业用地,,@
if re.match(r'^\d+', line) and ',' in line:
# 如果已经有一个地块在处理中,先保存它
if current_plot_started and current_points:
# 闭合多边形(首尾点相同)
if len(current_points) >= 3 and current_points[0] != current_points[-1]:
current_points.append(current_points[0])
if len(current_points) >= 4:
plots.append((current_attrs.copy(), current_points))
arcpy.AddMessage(u" 提取到地块: {} ({}个点)".format(
current_attrs.get("受让人", u"未知"), len(current_points)))
else:
arcpy.AddWarning(u" 地块点数不足 ({}个点),已跳过".format(len(current_points)))
# 重置当前地块
current_attrs = {}
current_points = []
# 解析新地块的属性
parts = line.split(',')
try:
if len(parts) >= 4:
current_attrs["受让人"] = parts[3].strip()
if len(parts) >= 7:
current_attrs["用途"] = parts[6].strip()
current_attrs["源文件"] = filename
current_plot_started = True
arcpy.AddMessage(u" 发现新地块: {}".format(current_attrs.get("受让人", u"未知")))
except Exception as e:
arcpy.AddWarning(u" 解析属性行失败: {} - 错误: {}".format(line, str(e)))
current_plot_started = False
continue
# 处理坐标行 - 格式: J1,1,2992679.6937,38595657.7082
if current_plot_started and (re.match(r'^[a-zA-Z]?\d+', line) or re.match(r'^\d+', line)):
parts = line.replace(',', ',').split(',')
try:
# 格式: J1,1,2992679.6937,38595657.7082
# 第三列是北坐标(y),第四列是东坐标(x)
if len(parts) >= 4 and parts[0].startswith('J'):
y = float(parts[2]) # 北坐标
x = float(parts[3]) # 东坐标
elif len(parts) >= 4:
# 尝试解析最后两个值为坐标
y = float(parts[-2])
x = float(parts[-1])
elif len(parts) >= 2:
# 只有坐标值的情况
y = float(parts[0])
x = float(parts[1])
else:
continue
current_points.append(arcpy.Point(x, y))
except (ValueError, IndexError) as e:
arcpy.AddWarning(u" 解析坐标行失败: {} - 错误: {}".format(line, str(e)))
# 处理文件末尾的地块
if current_plot_started and current_points:
# 闭合多边形(首尾点相同)
if len(current_points) >= 3 and current_points[0] != current_points[-1]:
current_points.append(current_points[0])
if len(current_points) >= 4:
plots.append((current_attrs.copy(), current_points))
arcpy.AddMessage(u" 提取到地块: {} ({}个点)".format(
current_attrs.get("受让人", u"未知"), len(current_points)))
else:
arcpy.AddWarning(u" 地块点数不足 ({}个点),已跳过".format(len(current_points)))
return plots
def create_output_feature_class(self, output_path, spatial_ref):
"""创建输出要素类"""
# 判断输出类型(shp或gdb)
if output_path.lower().endswith('.shp'):
workspace = os.path.dirname(output_path)
fc_name = os.path.basename(output_path)[:-4] # 去掉.shp扩展名
# 创建shapefile
arcpy.CreateFeatureclass_management(
out_path=workspace,
out_name=fc_name,
geometry_type="POLYGON",
spatial_reference=spatial_ref
)
output_fc = os.path.join(workspace, fc_name + ".shp")
else:
# 创建地理数据库要素类
arcpy.CreateFeatureclass_management(
out_path=os.path.dirname(output_path),
out_name=os.path.basename(output_path),
geometry_type="POLYGON",
spatial_reference=spatial_ref
)
output_fc = output_path
# 添加字段
arcpy.AddField_management(output_fc, "受让人", "TEXT", field_length=200)
arcpy.AddField_management(output_fc, "用途", "TEXT", field_length=100)
arcpy.AddField_management(output_fc, "源文件", "TEXT", field_length=255)
arcpy.AddField_management(output_fc, "地块序号", "LONG")
return output_fc
def process_folder(self, input_folder, spatial_ref, output_path):
"""处理文件夹中的所有TXT文件"""
# 检查输入文件夹
if not os.path.exists(input_folder):
arcpy.AddError(u"输入文件夹不存在: {}".format(input_folder))
return False
# 获取所有TXT文件
txt_files = []
for root, dirs, files in os.walk(input_folder):
for file in files:
if file.lower().endswith('.txt'):
txt_files.append(os.path.join(root, file))
if not txt_files:
arcpy.AddError(u"在文件夹中没有找到TXT文件")
return False
arcpy.AddMessage(u"找到 {} 个TXT文件".format(len(txt_files)))
# 创建输出要素类
arcpy.AddMessage(u"正在创建输出要素类...")
output_fc = self.create_output_feature_class(output_path, spatial_ref)
arcpy.AddMessage(u"输出要素类: {}".format(output_fc))
# 准备插入游标
fields = ["SHAPE@", "受让人", "用途", "源文件", "地块序号"]
# 统计信息
total_plots = 0
processed_files = 0
failed_files = 0
plot_counter = 0
# 开始处理文件
with arcpy.da.InsertCursor(output_fc, fields) as cursor:
for txt_file in txt_files:
filename = os.path.basename(txt_file)
arcpy.AddMessage(u"\n处理文件: {}".format(filename))
try:
# 读取文件内容
content = self.read_txt_file(txt_file)
if not content:
arcpy.AddWarning(u" 文件内容为空或读取失败")
failed_files += 1
continue
# 解析地块数据
plots = self.parse_txt_content(content, filename)
if plots:
# 插入每个地块
for attrs, points in plots:
try:
# 创建多边形
if len(points) >= 4:
array = arcpy.Array(points)
polygon = arcpy.Polygon(array)
# 准备属性值
assignee = attrs.get("受让人", u"未知")
purpose = attrs.get("用途", u"")
source_file = attrs.get("源文件", filename)
# 插入记录
cursor.insertRow([polygon, assignee, purpose, source_file, plot_counter + 1])
plot_counter += 1
total_plots += 1
except Exception as e:
arcpy.AddWarning(u" 创建多边形失败: {} - 错误: {}".format(
attrs.get("受让人", u"未知"), str(e)))
arcpy.AddMessage(u" 成功提取 {} 个地块".format(len(plots)))
processed_files += 1
else:
arcpy.AddWarning(u" 未提取到有效地块数据")
failed_files += 1
except Exception as e:
arcpy.AddWarning(u" 处理文件失败: {}".format(str(e)))
failed_files += 1
# 输出统计信息
arcpy.AddMessage(u"\n" + "=" * 60)
arcpy.AddMessage(u"处理完成!")
arcpy.AddMessage(u"成功处理文件数: {}".format(processed_files))
arcpy.AddMessage(u"失败文件数: {}".format(failed_files))
arcpy.AddMessage(u"总地块数: {}".format(total_plots))
arcpy.AddMessage(u"输出要素类: {}".format(output_fc))
arcpy.AddMessage(u"=" * 60)
return True
def main():
"""主函数 - ArcGIS脚本工具入口"""
try:
# 获取参数
input_folder = arcpy.GetParameterAsText(0)
spatial_ref = arcpy.GetParameter(1) # 空间参考对象
output_path = arcpy.GetParameterAsText(2)
# 验证参数
if not input_folder:
arcpy.AddError(u"请输入TXT文件夹路径")
return
if not output_path:
arcpy.AddError(u"请输入输出路径")
return
# 创建转换器对象
converter = TXTToFeatureConverter()
# 处理文件夹
success = converter.process_folder(input_folder, spatial_ref, output_path)
if success:
arcpy.AddMessage(u"\n转换成功完成!")
# 尝试刷新目录
try:
arcpy.RefreshCatalog(os.path.dirname(output_path))
arcpy.AddMessage(u"目录已刷新")
except:
pass
else:
arcpy.AddError(u"转换失败!")
except Exception as e:
arcpy.AddError(u"执行错误: {}".format(str(e)))
import traceback
arcpy.AddError(traceback.format_exc())
if __name__ == "__main__":
main()
三、参数设置
# 获取参数
input_folder = arcpy.GetParameterAsText(0)
spatial_ref = arcpy.GetParameter(1) # 空间参考对象
output_path = arcpy.GetParameterAsText(2)
根据功能代码中输入参数的个数和顺序设置交互页面参数。
如上代码所示,BatchDeleteTables有两个输入参数:参数(0),参数(1),参数(2)。
交互页面设置对应的三个参数:TXT文件所在文件夹路径;投影坐标系;矢量输出路径。

四、功能测试
浏览TXT文件夹所在路径;选择对应的空间参考;设置矢量文件输出路径。



这里测试只放了一个txt文件,多个txt也是正常转的。矢量文件中的字段是根据之前的需求随便写的,可以自行修改。【源文件】记录的是生成当前要素的txt文件名,便于溯源。
这段代码有的时候会显示提取失败,目前还不能确定什么原因导致的。测试过几次,可能是文件被莫名其妙地锁住了,把待转换的txt文件换在别的路径下,又能正常执行了。反正如果有问题就多试几下,换路径或关闭软件重新打开,或者清理一下temp文件。
8794

被折叠的 条评论
为什么被折叠?



