You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用PySpark结合Schema DataFrame读取固定宽度文本文件

使用PySpark解析固定宽度文本文件(基于Schema DataFrame)

问题描述

现有如下固定宽度格式的文本文件:

00120181120xyz12341
00220180203abc56792
00320181203pqr25483

同时存在一个Schema DataFrame,包含两列:_Name(目标列名)和_Length(对应列的宽度)。需要将上述文本文件转换为如下格式的DataFrame:

#+---+-----+---+
#|C1 |  C2 |C3 |
#+---+-----+---+
#|0  |02018|11 |
#|0  |02018|02 |
#|0  |02018|12 |
#+---+-----+---+

解决方案

步骤1:读取固定宽度文本文件

先读取文本文件,得到包含原始文本行的DataFrame:

raw_df = spark.read.text("/path/to/your/fixed_width_file.txt")

步骤2:准备Schema DataFrame

假设你的Schema DataFrame已经存在,这里我们模拟一个符合目标输出的示例(如果是从外部加载,替换为对应的读取逻辑即可):

from pyspark.sql import SparkSession
from pyspark.sql.window import Window
from pyspark.sql.functions import sum, col, substring

# 初始化SparkSession(如果未初始化)
spark = SparkSession.builder.appName("FixedWidthParser").getOrCreate()

# 模拟Schema DataFrame
schema_df = spark.createDataFrame(
    [("C1", 1), ("C2", 5), ("C3", 2)],
    ["_Name", "_Length"]
)

步骤3:计算字段的起始/结束位置

使用窗口函数计算每个字段在固定宽度行中的起始偏移量:

# 定义窗口,按列的顺序(假设Schema DataFrame的顺序就是文本中字段的顺序)
window = Window.orderBy("_Name")

# 计算累计长度,得到每个字段的起始位置(起始位置=前序字段总长度)
schema_with_pos = schema_df.withColumn(
    "start_pos",
    sum("_Length").over(window.rowsBetween(Window.unboundedPreceding, Window.currentRow - 1))
).withColumn(
    "end_pos",
    col("start_pos") + col("_Length")
)

步骤4:动态生成截取表达式

遍历Schema的行,生成substring表达式来拆分每个字段:

# 收集Schema的字段信息
schema_fields = schema_with_pos.collect()

# 生成截取表达式
select_expr = []
for field in schema_fields:
    col_name = field["_Name"]
    start = field["start_pos"] + 1  # Spark的substring是1-based索引
    length = field["_Length"]
    select_expr.append(substring(col("value"), start, length).alias(col_name))

步骤5:生成目标DataFrame

应用表达式并查看结果:

target_df = raw_df.select(*select_expr)
target_df.show()

执行后就会得到你需要的格式的DataFrame。


内容的提问来源于stack exchange,提问作者João Miguens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:00:58