Python怎么批量读取文件夹内的所有图片
详细讲解在Python中批量读取文件夹内所有图片的实用方法,包含pathlib、os.walk、Pillow与OpenCV的完整代码实现、多级子目录递归、中文路径容错及生成器内存优化。
在 Python 中批量读取文件夹内的图片,本质上分为两个独立阶段:首先是文件路径检索与筛选,找到目标目录下所有合法的图片文件;其次是数据载入与内存管理,根据任务需求选用 Pillow、OpenCV 或生成器按需解析图片数据。最推荐且符合现代 Python 规范的实现是使用标准库 pathlib 搭配 Pillow 库,兼顾代码优雅性、跨平台兼容与执行稳定性。
一、推荐做法:使用 pathlib 与 Pillow 批量读取
pathlib 是 Python 3 内置的标准库,面向对象地管理路径,能自动处理 Windows 反斜杠与 Linux 正斜杠的差异;Pillow(导入名为 PIL)则是 Python 处理图片最主流的第三方库。安装命令非常直接:
pip install Pillow
1. 读取当前文件夹下的所有图片(非递归)
如果图片都在同一个文件夹的一级目录下,不需要扫描子文件夹,可以使用 Path.iterdir() 或 Path.glob():
from pathlib import Path
from PIL import Image
def load_images_from_folder(folder_path):
# 支持的常见图片后缀,转小写对比
valid_extensions = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
images = []
target_dir = Path(folder_path)
if not target_dir.is_dir():
print(f"指定的目录不存在: {folder_path}")
return images
# 遍历该目录下的直接子文件
for item in target_dir.iterdir():
if item.is_file() and item.suffix.lower() in valid_extensions:
try:
# 使用 with 上下文确保读取数据后关闭底层文件句柄
with Image.open(item) as img:
# 复制一份图像数据到内存中,避免上下文退出后文件句柄关闭失效
images.append((item.name, img.copy()))
except Exception as e:
print(f"无法读取图片 {item.name}: {e}")
print(f"成功读取 {len(images)} 张图片")
return images
# 调用示例
# image_list = load_images_from_folder("./photos")
2. 递归读取包含多级子目录的所有图片
当图片分散存放在多级子分类文件夹中时,可以使用 Path.rglob("*") 进行深度递归遍历:
from pathlib import Path
from PIL import Image
def load_images_recursively(folder_path):
valid_extensions = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
target_dir = Path(folder_path)
loaded_data = []
# rglob("*") 递归检索所有层级的子文件
for file_path in target_dir.rglob("*"):
if file_path.is_file() and file_path.suffix.lower() in valid_extensions:
try:
with Image.open(file_path) as img:
loaded_data.append({
"path": str(file_path),
"size": img.size, # (宽, 高)
"mode": img.mode, # RGB / RGBA / L
"image": img.copy()
})
except Exception as e:
print(f"文件损坏或无法解析: {file_path},原因: {e}")
return loaded_data
二、主流读取方案的技术选型与对比
在面对不同体量、不同结构和不同业务场景时,Python 提供了多种工具组合。下表和对比图给出了主流方案的特性分析:
三、海量图片场景:生成器(Generator)与内存优化
当文件夹包含几万张高分辨率图片时,严禁使用列表把所有图片一次性 append 进来。每张 4K 图片解码后占用的内存可能高达数十兆,几千张图片就会消耗几十 GB 内存导致系统发生 OOM(内存溢出崩溃)。
使用 Python 关键字 yield 将函数改造为生成器:读一张、处理一张、释放一张,内存始终处于安全稳定状态:
from pathlib import Path
from PIL import Image
def image_stream(folder_path):
"""生成器:逐张产出图片路径与图像对象,避免内存占用过大"""
valid_exts = {".jpg", ".jpeg", ".png", ".webp"}
for p in Path(folder_path).rglob("*"):
if p.is_file() and p.suffix.lower() in valid_exts:
try:
# 仅在需要时打开图片
with Image.open(p) as img:
yield p, img
except Exception as err:
print(f"跳过不可读文件 {p}: {err}")
# 使用方式:消费生成器
# for path, img in image_stream("./large_dataset"):
# # 执行当前图像的处理逻辑(如缩放、特征提取或保存)
# print(f"处理完成: {path.name}, 尺寸: {img.size}")
# # 循环单次结束,img 离开作用域被垃圾回收
四、避坑指南:中文路径、损坏文件与特殊格式
1. OpenCV 中文路径读取失败问题
在使用 cv2.imread() 读取图片时,如果文件路径中包含中文字符,在 Windows 系统下经常会直接返回 None 而不报错。推荐的通用解决方案是先用 np.fromfile 读取二进制字节流,再通过 cv2.imdecode 解码:
import cv2
import numpy as np
from pathlib import Path
def cv2_read_image(image_path):
"""支持中文路径与特殊字符的 OpenCV 图像读取函数"""
try:
# np.fromfile 支持包含中文的文件路径
img_array = np.fromfile(str(image_path), dtype=np.uint8)
# 解码为彩色图像 (BGR)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
return img
except Exception as e:
print(f"解码失败: {image_path}, 错误: {e}")
return None
# 批量搭配使用
def batch_read_opencv(folder):
for p in Path(folder).glob("*.jpg"):
img = cv2_read_image(p)
if img is not None:
# 正常处理 (OpenCV 读取出的形状为 H x W x C)
h, w, c = img.shape
2. 常见异常捕获与过滤
文件夹中常常混入重命名伪装文件(如将文本文件改后缀为 .jpg)、被操作系统锁定的临时文件(如 macOS 下的 ._DS_Store 或 ._*.jpg)。建议在遍历时加入前缀过滤:
# 排除系统隐藏文件和 macOS 资源分支文件
if file_path.name.startswith((".", "._")):
continue
五、实战总结与决策指南
针对不同开发需求,可参考以下路径直接锁定最合适你的代码组合:
pathlib.Path.rglob(),打开图片用 with Image.open(),量大必用 yield 生成器,遇中文路径选 np.fromfile + cv2.imdecode。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













