
本文介绍一种内存友好的方法:使用 os.scandir() 替代 os.listdir(),避免在大型数据集目录中因一次性加载所有文件名导致 vs code 崩溃,从而安全、高效地随机采样指定数量(如 64 张)图像用于 pytorch dataloader 构建。
本文介绍一种内存友好的方法:使用 os.scandir() 替代 os.listdir(),避免在大型数据集目录中因一次性加载所有文件名导致 vs code 崩溃,从而安全、高效地随机采样指定数量(如 64 张)图像用于 pytorch dataloader 构建。
在处理大规模图像数据集(例如含数万张 PNG 文件的文件夹)时,直接调用 os.listdir(path) 会将所有文件名一次性读入内存,这不仅耗时,还极易引发 IDE(如 VS Code)无响应或崩溃——尤其当工作区索引未优化或系统内存受限时。而 os.scandir() 是 Python 3.5+ 引入的底层替代方案,它返回一个可迭代的 DirEntry 对象流,支持惰性遍历与属性预获取(如 is_file()),显著降低内存开销。
以下是一个轻量、可靠且可直接集成进数据加载流程的实现:
import os
import random
def sample_k_files_from_dir(directory: str, k: int, exts: tuple = (".png", ".jpg", ".jpeg")) -> list:
"""
从指定目录中随机采样 k 个匹配扩展名的文件路径(不预先加载全部文件名)
Args:
directory: 目标目录路径
k: 期望采样数量
exts: 允许的文件扩展名元组(小写校验)
Returns:
长度为 k 的绝对路径字符串列表
"""
# 使用 scandir 惰性遍历,仅收集符合条件的文件名
candidates = []
with os.scandir(directory) as it:
for entry in it:
if entry.is_file() and entry.name.lower().endswith(exts):
candidates.append(entry.name)
# 边界检查:确保有足够文件可供采样
if len(candidates) < k:
raise ValueError(f"Directory '{directory}' contains only {len(candidates)} matching files, but {k} are required.")
# 随机采样(无放回)
sampled_names = random.sample(candidates, k=k)
return [os.path.join(directory, name) for name in sampled_names]
# 示例用法:为 DataLoader 准备一个 batch
data_dir = "data/images"
batch_size = 64
try:
batch_paths = sample_k_files_from_dir(data_dir, k=batch_size)
print(f"✅ Successfully loaded {len(batch_paths)} image paths.")
# 此处可进一步用 PIL/OpenCV 加载图像,或传入自定义 Dataset
except ValueError as e:
print(f"❌ Sampling failed: {e}")✅ 关键优势说明:
- os.scandir() 在遍历时不构建完整列表,内存占用与目录中实际匹配文件数成正比,而非总条目数;
- 使用 with 语句确保资源及时释放,避免句柄泄漏;
- 扩展名校验采用 .lower().endswith(...),兼容大小写混杂的文件命名;
- 显式异常提示不足样本场景,便于调试与容错。
⚠️ 注意事项:
- 若需更高性能(如十亿级文件),应考虑基于 pathlib.Path.iterdir() + itertools.islice 的流式抽样,或改用 glob + random.shuffle() 分块策略;
- random.sample() 要求 k ≤ len(candidates),务必做前置校验;
- 在多进程 DataLoader(如 PyTorch num_workers > 0)中,该函数需保证线程安全——当前实现无共享状态,天然安全。
综上,os.scandir() 是替代 os.listdir() 进行高效、低内存随机文件采样的首选方案。它既满足快速构建训练 batch 的工程需求,又规避了大型数据集带来的稳定性风险,是数据加载管道中值得标准化的一环。









