如何逆向解析大型机COBOL固定宽度文件并导入Pandas?
大型机COBOL固定宽度文件解析及Pandas导入方案
一、先处理文件读取与编码问题
- 已确认每行固定437字节,先以二进制模式读取,避免编码干扰,再按固定宽度拆分:
with open('目标文件.dat', 'rb') as f: lines = [] while True: line = f.read(437) if not line: break lines.append(line) - 文本字段(如日期)用
cp037或cp1140解码,二进制字段(如COMP-3类型)保留字节串,后续单独解析。
二、解析COMP-3(压缩十进制)及尾符号字段
从你提供的DTD示例来看,CSTCTL_MO_YR字段为S9(5) COMP-3,物理长度3字节,带TRAILING_SIGN:
- COMP-3字段规则:每个字节存储两位十进制数,最后一个字节的低4位表示符号(0xC=正,0xD=负,0xF=无符号)
- 手动解析示例(比
struct更直观):def parse_comp3(bs): digits = [] sign = '+' # 遍历每个字节 for idx, b in enumerate(bs): if idx == len(bs) - 1: # 最后字节:高4位是最后一位数字,低4位是符号 digit = (b >> 4) & 0x0F sign_bit = b & 0x0F digits.append(str(digit)) if sign_bit == 0xD: sign = '-' else: # 前序字节:高低4位各存一位数字 digits.append(str((b >> 4) & 0x0F)) digits.append(str(b & 0x0F)) # S9(5)对应5位数字,取前5位拼接 num_str = ''.join(digits[:5]) return float(f"{sign}{num_str}") # 针对DTD中CSTCTL_MO_YR字段(物理偏移69,长度3) sample_val = parse_comp3(lines[0][69:69+3]) print(sample_val) - 你看到的
ç是用文本编码解码二进制COMP-3字段导致的乱码,这类字段不能按文本处理,必须按压缩十进制规则解析。
三、批量导入Pandas的两种方法
方法1:自定义字段映射+逐行解析
- 根据DTD整理字段元数据:
field_specs = [ # 示例:对应DTD中的CSTCTL_MO_YR { 'name': 'CSTCTL_MO_YR', 'type': 'comp3', 'physical_offset': 69, 'physical_length': 3 }, # 添加其他文本字段示例 { 'name': 'file_date', 'type': 'text', 'physical_offset': 0, # 替换为实际偏移 'physical_length': 8, # 替换为实际长度 'encoding': 'cp037' } ] - 解析所有行并转为DataFrame:
import pandas as pd def parse_line(line, specs): row = {} for spec in specs: segment = line[spec['physical_offset']:spec['physical_offset']+spec['physical_length']] if spec['type'] == 'comp3': row[spec['name']] = parse_comp3(segment) elif spec['type'] == 'text': row[spec['name']] = segment.decode(spec['encoding']).strip() return row parsed_rows = [parse_line(line, field_specs) for line in lines] df = pd.DataFrame(parsed_rows)
方法2:用read_fwf结合转换器
如果多数是文本字段,仅少数为COMP-3,可先按固定宽度读取文本,再单独处理二进制字段:
# 生成字段位置列表(物理起始-结束索引) colspecs = [(s['physical_offset'], s['physical_offset']+s['physical_length']) for s in field_specs] col_names = [s['name'] for s in field_specs] # 先以文本模式读取所有字段 df_raw = pd.read_fwf('目标文件.dat', colspecs=colspecs, names=col_names, header=None, encoding='cp037', dtype=str) # 单独转换COMP-3字段 df_raw['CSTCTL_MO_YR'] = df_raw['CSTCTL_MO_YR'].apply(lambda x: parse_comp3(x.encode('cp037')))
内容的提问来源于stack exchange,提问作者Nicholas Lawrence
相关产品推荐
相关产品推荐

