如何批量读取TXT文件转为Pandas DataFrame?解决StopIteration错误
批量处理TXT文件生成带头部信息的DataFrame并保存为CSV
问题背景
有多个格式如下的TXT文件,需要提取文件头部的城市、身高、体重、年龄信息,添加为DataFrame的新列,最终将每个文件转换为指定结构的CSV:
Person:?,?;F dob. ? MT: ? Z:C NewYork Mon.:S St.?
144 cm/35 Kg/5 YearsOld
45,34,22,26,0
78,74,82,11,0
已实现单个文件的转换代码,但放入循环用glob批量处理时出现StopIteration错误,目标生成如下结构的DataFrame并保存:
A, B, C, D, E, height, weight, age, city 45,34,22,26,0, 144, 35, 5, NewYork 78,74,82,11,0, 144, 35, 5, NewYork
错误原因
原代码中[next(f) for _ in range(3)]强制读取文件前3行,若部分文件的头部行数量不足3行(或空行位置不同),next()会因无法获取下一行抛出StopIteration异常。另外原代码依赖固定行数跳过数据行,容错性差。
解决方案
改用更健壮的方式读取头部信息,遍历所有TXT文件处理:
完整批量处理代码
import pandas as pd import re from glob import glob # 遍历文件夹内所有TXT文件,可替换为指定路径如"./data/*.txt" for txt_file in glob("*.txt"): city = None height = weight = age = None data_start_pos = 0 # 解析头部信息 with open(txt_file, 'r') as f: for line in f: stripped_line = line.strip() # 提取Z:C后的城市名 if "Z:C" in stripped_line: city_match = re.search(r'Z:C (\w+)', stripped_line) if city_match: city = city_match.group(1) # 提取身高、体重、年龄 if "cm" in stripped_line.lower() and "kg" in stripped_line.lower(): numbers = re.findall(r'\d+', stripped_line) if len(numbers) >= 3: height, weight, age = map(int, numbers[:3]) # 定位数据起始行(非空且为数字逗号分隔格式) if stripped_line and all(c.isdigit() or c == ',' for c in stripped_line): data_start_pos = f.tell() - len(line) break # 读取数据生成DataFrame df = pd.read_csv(txt_file, skiprows=lambda x: x < data_start_pos//len(line), sep=',', index_col=None, names=['A','B','C','D','E']) # 添加头部信息列 df['height'] = height df['weight'] = weight df['age'] = age df['city'] = city # 保存为同名CSV文件 csv_filename = txt_file.replace('.txt', '.csv') df.to_csv(csv_filename, index=False)
代码说明
- 头部解析优化:逐行读取直到找到目标信息,不依赖固定行数,彻底避免
StopIteration;用正则精准匹配城市和数值,提升解析准确性。 - 数据读取优化:通过文件指针位置确定数据起始行,适配不同空行数量的文件,替代硬编码的
skiprows=8。 - 批量处理:用
glob批量获取所有TXT文件,逐个处理后自动保存为同名CSV。
内容的提问来源于stack exchange,提问作者dspractician
相关产品推荐
相关产品推荐

