Python批量读取文件夹下所有指定格式文件
批量读取指定格式文件是数据处理、日志分析和日常办公自动化中的高频任务。在实际开发中,最直接高效的解决路径是使用Python标准库提供的 pathlib 模块,搭配通配符匹配快速锁定文件路径,再配合对应的文件读取库完成内容加载。针对不同的目录嵌套层级与匹配精度,也可以选用 glob 模块或 os.walk()。本文将具体讲解操作步骤、不同方案的代码实现以及常见边界问题的处理策略。
一、批量读取的标准处理流程
无论是处理 CSV、Excel、JSON 还是普通文本文件,批量读取的逻辑均由“定位路径、筛选后缀、建立迭代、解析内容与异常保护”五个关键环节构成。梳理清楚整个链条,有助于写出逻辑清晰、健壮稳定的批处理程序。
二、主流读取方案与代码实现
Python 提供了多种模块用于遍历文件系统。根据现代 Python 编码规范,优先推荐使用标准库 pathlib,它具备面向对象的语法且天然跨平台;在特定需要通配符字符串的场景下可使用 glob;在需要细粒度干预目录遍历行为时,可使用 os.walk()。
方法一:使用 pathlib 模块(现代标准库首选)
pathlib 自 Python 3.4 引入,处理路径时无需拼接字符串,且返回的 Path 对象自带丰富的属性和检测方法(如 .name、.suffix、.is_file())。
from pathlib import Path
# 1. 定义目标文件夹路径
target_dir = Path("./data_folder")
# 2. 单层扫描:仅获取当前目录下的所有 .csv 文件
csv_files_single = list(target_dir.glob("*.csv"))
# 3. 递归扫描:获取包含所有子目录下的 .csv 文件
csv_files_recursive = list(target_dir.rglob("*.csv"))
# 4. 打印扫描到的文件列表
print(f"找到单层 CSV 文件数量: {len(csv_files_single)}")
for file_path in csv_files_single:
print(f"文件名: {file_path.name} | 完整路径: {file_path}")
执行输出示例(仅作结果展示参考):
找到单层 CSV 文件数量: 3
文件名: sales_q1.csv | 完整路径: data_folder/sales_q1.csv
文件名: sales_q2.csv | 完整路径: data_folder/sales_q2.csv
文件名: sales_q3.csv | 完整路径: data_folder/sales_q3.csv
方法二:使用 glob 模块(简练的通配符检索)
glob 模块支持类似 Unix Shell 的文件名扩展规则。其优势是返回值为普通字符串列表,适合直接与接受字符串路径的传统函数协作。
import glob
import os
target_folder = "./data_folder"
# 单层匹配
pattern_single = os.path.join(target_folder, "*.xlsx")
xlsx_files = glob.glob(pattern_single)
# 递归匹配子文件夹(需显式设置 recursive=True 并配合 ** 规则)
pattern_recursive = os.path.join(target_folder, "**", "*.xlsx")
all_xlsx_files = glob.glob(pattern_recursive, recursive=True)
print(f"匹配到 Excel 文件数: {len(all_xlsx_files)}")
方法三:使用 os.walk()(复杂层级精细遍历)
os.walk() 能够以自顶向下(或自底向上)遍历目录树,每次迭代返回三元组 (dirpath, dirnames, filenames)。当遍历过程中需要动态跳过某些子文件夹(例如忽略名为 backup 或 temp 的目录)时,os.walk() 最为便捷。
import os
target_directory = "./data_folder"
matched_files = []
for root, dirs, files in os.walk(target_directory):
# 可直接在遍历中修改 dirs 列表以排除特定目录
if "archive" in dirs:
dirs.remove("archive")
for filename in files:
if filename.endswith(".json"):
full_path = os.path.join(root, filename)
matched_files.append(full_path)
print(f"扫描到的有效 JSON 文件: {matched_files}")
三、通配符匹配机制与关键过滤细节
在实际批量读取中,直接匹配扩展名往往会遇到多重干扰,例如大小写不一致、操作系统隐藏文件以及办公软件生成的临时文件。了解匹配机制并做好过滤是确保程序健壮性的关键。
1. 单层与多层递归的模式差异
在通配符体系中,单个星号 *.csv 仅匹配当前目录下的文件名,不会进入子目录;而双星号 **/*.csv 配合递归参数会向下穿透所有层级的子目录。
2. 扩展名大小写兼容处理
在 Linux 等区分大小写的文件系统中,.csv 与 .CSV 是两个完全不同的后缀。若直接检索 *.csv,可能会遗漏相机导出的照片(如 .JPG)或某些特定系统导出的文件。推荐使用后缀大小写归一化检查:
from pathlib import Path
target_dir = Path("./incoming_files")
# 同时抓取 .csv 与 .CSV,或在遍历时比对 .lower()
valid_files = [
p for p in target_dir.iterdir()
if p.is_file() and p.suffix.lower() == ".csv"
]
3. 忽略临时文件与隐藏文件
Microsoft Excel 在打开 report.xlsx 时,会在同目录下自动生成名为 ~$report.xlsx 的隐藏锁定文件;macOS 也会在文件夹下生成 .DS_Store。如果直接交给 Pandas 或 openpyxl 解析,必然触发文件损坏异常。必须在读取前排除这些文件:
# 排除以 ~$ 开头的 Office 临时文件及以 . 开头的隐藏文件
clean_files = [
f for f in target_dir.glob("*.xlsx")
if not f.name.startswith("~$") and not f.name.startswith(".")
]
四、完整读取与内容聚合实战
获取到有效文件路径列表后,下一步是打开文件并整合其内容。根据文件类型不同,通常分为表格数据(如 CSV、Excel)与文本内容(如 TXT、JSON、LOG)。
实战一:批量读取 CSV 并合并为单个 DataFrame
在数据分析工作中,通常需要将分散在各个分公司或各日期的 CSV 表格拼装在一起。配合 pandas 库,可以用极少代码完成这一操作:
import pandas as pd
from pathlib import Path
data_directory = Path("./sales_records")
# 1. 获取所有合法 csv 文件路径
csv_files = [
p for p in data_directory.glob("*.csv")
if not p.name.startswith("~")
]
# 2. 逐一读取并存入列表
data_frames = []
for file_path in csv_files:
try:
# 读取单个表格,可在此添加特定源文件名标记列
df = pd.read_csv(file_path, encoding="utf-8")
df["source_file"] = file_path.name
data_frames.append(df)
except Exception as e:
print(f"读取文件 {file_path.name} 失败,原因: {e}")
# 3. 纵向合并所有数据表
if data_frames:
combined_df = pd.concat(data_frames, ignore_index=True)
print(f"成功合并 {len(data_frames)} 个文件,总数据行数: {len(combined_df)}")
else:
print("未找到有效的数据文件")
实战二:批量读取文本文件并提取核心内容
对于日志文件或普通文本,采用 Python 原生上下文管理器 with open() 逐个读取,确保文件句柄在使用完毕后立即关闭,释放系统资源。
from pathlib import Path
log_dir = Path("./system_logs")
log_contents = {}
for log_file in log_dir.glob("*.log"):
# 显式指定编码,避免在 Windows 环境下默认使用 gbk 导致解码崩溃
try:
with open(log_file, "r", encoding="utf-8", errors="ignore") as f:
lines = f.readlines()
log_contents[log_file.name] = len(lines)
print(f"文件 {log_file.name} 读取完成,行数: {len(lines)}")
except IOError as err:
print(f"访问文件 {log_file.name} 出错: {err}")
encoding="utf-8"。若文件源可能包含其他编码格式(如部分 Windows 导出的 ANSI/GBK 格式),可在捕获 UnicodeDecodeError 时回退尝试 encoding="gb18030"。
五、选型指南与常见问题避坑清单
为了让不同规模的项目都能快速选定最合适的处理逻辑,下表列出了常见需求与处理模式的映射关系:
| 应用场景 | 推荐方案 | 核心代码特征 | 主要优势 |
|---|---|---|---|
| 日常数据处理 / 现代项目首选 | pathlib.Path.glob() |
Path(dir).glob("*.csv") |
面向对象、语法优雅、无需拼接路径 |
| 跨多级深层子目录递归检索 | pathlib.Path.rglob() |
Path(dir).rglob("*.xlsx") |
递归逻辑简洁、一行代码穿透子目录 |
| 需与仅接收字符串的第三方库协作 | glob.glob() |
glob.glob("./dir/**/*.json") |
直接返回字符串数组,通配符语义清晰 |
| 复杂嵌套且需按目录名排除分支 | os.walk() |
for root, dirs, files in os.walk() |
可就地修改 dirs 阻止进入无关分支 |
掌握了上述 pathlib 与 glob 的结合使用方式,并在读取前加入针对临时文件和大小写后缀的过滤逻辑,即可稳定应对绝大多数批量文件读取与汇总任务。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









