PySpark如何读取目录下多个.xlsx文件并合并为单个Spark数据帧
PySpark合并指定目录下所有同schema xlsx文件的实现方案
最优实现(原生Spark读取,性能最好)
前提:提前将对应Spark版本的spark-excel连接器加入运行依赖,启动spark时可通过--packages com.crealytics:spark-excel_2.12:3.5.0_0.20.3指定(版本号需和你使用的Spark版本匹配)。
该方案无需手动遍历文件,Spark原生支持通配符批量读取同格式文件,效率远高于逐文件转换合并。
from pyspark.sql import SparkSession spark = SparkSession.builder.appName("merge_xlsx").getOrCreate() # 通配符匹配目录下所有xlsx文件 excel_path = "/Users/UserName/Documents/excel/*.xlsx" msdf = spark.read.format("com.crealytics.spark.excel") \ .option("header", "true") \ .option("sheetName", "Analog Voltage Input") \ .option("inferSchema", "false") \ # 提前定义好schema的话可直接传入,避免类型推断误差 # .schema(custom_schema) .load(excel_path)
备选实现(依赖pandas读取转换,适配无spark-excel连接器场景)
如果环境无法安装额外依赖,只能用pandas中转,可参考如下修正后的代码:
import os import re import pandas as pd from pyspark.sql import SparkSession spark = SparkSession.builder.appName("merge_xlsx").getOrCreate() dir_root = "/Users/UserName/Documents/excel/" file_list = os.listdir(dir_root) # 修正正则,严格匹配后缀为xlsx的文件 xlsx_pattern = r'.*\.xlsx$' merged_sdf = None for file_name in file_list: if re.match(xlsx_pattern, file_name): # 拼接完整路径,避免读取时找不到文件 full_file_path = os.path.join(dir_root, file_name) # 读取当前文件指定sheet current_pdf = pd.read_excel(full_file_path, sheet_name="Analog Voltage Input") current_sdf = spark.createDataFrame(current_pdf) # 合并数据帧 if merged_sdf is None: merged_sdf = current_sdf else: # 用unionByName替代union,避免列顺序不一致导致的合并错误 merged_sdf = merged_sdf.unionByName(current_sdf)
原代码核心问题说明
- 循环内每次读取两个文件、调用
next(file)逻辑错误,file是字符串类型不是迭代器,运行会直接报错 - 每次循环都会覆盖合并结果
msdf,最终只能得到最后两个文件的合并结果,前面读取的文件数据全部丢失 - 未拼接完整文件路径,
os.listdir仅返回文件名,直接传入pandas.read_excel会找不到文件 - 正则匹配规则不严谨,会误匹配文件名中间带xlsx字符的非xlsx文件
内容的提问来源于stack exchange,提问作者Jogibaer
相关产品推荐
相关产品推荐

