文件批量读取与路径管理:用os和glob玩转文件夹

做光谱分析,最头疼的是什么?

我个人觉得,不是算法多复杂,也不是数据多难处理。而是——你得先搞定那一堆乱七八糟的文件。

你想想看,一次实验下来,少说几十个光谱文件。命名方式五花八门,有的带日期,有的带样品编号,有的干脆就叫"新建文件夹"。更别提不同操作系统下,路径分隔符还不一样。Windows用反斜杠,Linux用正斜杠,Mac有时候还搞特殊。

嗯,今天我们就来聊聊怎么优雅地搞定这件事。

为什么非得用os和glob?

说白了,手动一个一个文件去处理,那是刚入行才干的事。我刚开始做光谱分析那会儿,也傻乎乎地手动改文件名、手动复制路径。直到有一次,我连续处理了200多个文件,眼睛都快瞎了,还漏掉了3个。

从那以后,我就养成了一个习惯:能用脚本解决的,绝不动手。

Python的os模块和glob模块,就是干这个的。前者负责跟操作系统打交道,后者专门帮你找文件。

核心思路: 用代码代替手动操作,让脚本自己去遍历文件夹、过滤文件名、构建路径列表。

os模块:跟操作系统对话的基础

os模块是Python内置的,不需要额外安装。它提供了很多跟操作系统交互的函数。

获取当前路径

import os

# 获取当前工作目录
current_dir = os.getcwd()
print(f"当前目录:{current_dir}")

# 列出目录下所有文件和文件夹
all_items = os.listdir(current_dir)
print(f"目录内容:{all_items}")

我在项目中遇到过一个问题:有时候脚本跑着跑着,路径就乱了。后来我习惯在脚本开头先os.chdir()到固定目录,这样就不会迷路。

路径拼接——别再用加号了

很多人喜欢用字符串加号拼接路径,比如path = folder + "/" + filename。这种做法,说实话,挺危险的。

为什么?因为不同操作系统的分隔符不一样。你写死在代码里的正斜杠,到了Windows上可能就报错。

# 正确做法:用 os.path.join()
folder = "data/spectra"
filename = "sample_001.csv"
full_path = os.path.join(folder, filename)
print(full_path)
# Windows 输出:data\spectra\sample_001.csv
# Linux/Mac 输出:data/spectra/sample_001.csv

看到了吗?os.path.join会自动根据当前操作系统选择正确的分隔符。这个细节,我曾经吃过亏。有一次把写好的脚本发给同事,他在Mac上跑,路径全乱了。从那以后,我再也不用加号拼路径了。

判断文件还是文件夹

import os

path = "some_file.txt"
if os.path.isfile(path):
    print("这是一个文件")
elif os.path.isdir(path):
    print("这是一个文件夹")
else:
    print("路径不存在")
小技巧:os.path.exists() 先判断路径是否存在,可以避免很多莫名其妙的报错。

glob模块:文件搜索利器

glob模块,说白了就是帮你做文件匹配的。它支持通配符,用起来非常方便。

基础用法

import glob

# 查找当前目录下所有 .csv 文件
csv_files = glob.glob("*.csv")
print(csv_files)

# 递归查找子目录
all_csv = glob.glob("**/*.csv", recursive=True)
print(all_csv)

这里有个坑,我提醒一下:recursive=True这个参数,在Python 3.5以上才支持。如果你还在用老版本,记得升级。

结合正则表达式过滤文件名

有时候,光靠通配符不够用。比如你想找出所有以"sample_"开头、后面跟三位数字的.csv文件。这时候就得请出正则表达式了。

import glob
import re

# 先用 glob 拿到所有 .csv 文件
all_csv = glob.glob("*.csv")

# 再用正则过滤
pattern = r"^sample_\d{3}\.csv$"
filtered = [f for f in all_csv if re.match(pattern, f)]

print(filtered)

我个人习惯把正则表达式写成一个函数,方便复用:

def filter_files(file_list, pattern):
    """根据正则表达式过滤文件名"""
    return [f for f in file_list if re.match(pattern, f)]

# 使用示例
csv_files = glob.glob("*.csv")
target_files = filter_files(csv_files, r"^sample_\d{3}\.csv$")
注意: 正则表达式匹配的是文件名,不是完整路径。如果你需要匹配路径中的目录名,记得把路径也考虑进去。

构建文件路径列表——实战案例

好了,理论说完了。我们来看一个完整的实战案例。

假设你的光谱数据存放在这样的目录结构中:

data/
├── 2024-01/
│   ├── sample_001.csv
│   ├── sample_002.csv
│   └── sample_003.csv
├── 2024-02/
│   ├── sample_004.csv
│   ├── sample_005.csv
│   └── sample_006.csv
└── 2024-03/
    ├── sample_007.csv
    ├── sample_008.csv
    └── sample_009.csv

你想批量读取所有以"sample_"开头的.csv文件。怎么做?

import os
import glob
import re

def build_file_list(root_dir, pattern):
    """
    构建文件路径列表
    
    参数:
        root_dir: 根目录
        pattern: 文件名正则表达式
    返回:
        匹配的文件路径列表
    """
    # 递归查找所有 .csv 文件
    all_csv = glob.glob(os.path.join(root_dir, "**", "*.csv"), recursive=True)
    
    # 过滤文件名
    filtered = []
    for file_path in all_csv:
        filename = os.path.basename(file_path)
        if re.match(pattern, filename):
            filtered.append(file_path)
    
    return filtered

# 使用示例
root = "data"
pattern = r"^sample_\d{3}\.csv$"
file_list = build_file_list(root, pattern)

print(f"找到 {len(file_list)} 个文件:")
for f in file_list:
    print(f)

这段代码,我用了好几年,基本没出过问题。你拿去稍微改改,就能用在你的项目里。

处理不同操作系统的路径差异

这个问题,说实话,挺烦人的。但也不是没办法解决。

统一使用正斜杠

Python的pathlib模块(Python 3.4+)提供了一个更现代的方式:

from pathlib import Path

# 创建路径对象
path = Path("data/spectra/sample_001.csv")
print(path)  # 自动使用当前系统的分隔符

# 路径拼接
folder = Path("data/spectra")
full_path = folder / "sample_001.csv"
print(full_path)

# 获取文件名、目录名
print(path.name)      # sample_001.csv
print(path.stem)      # sample_001
print(path.suffix)    # .csv
print(path.parent)    # data/spectra

我个人更推荐用pathlib,因为它更直观,代码也更简洁。不过如果你在维护老项目,可能还是得用os.path

跨平台路径转换

import os

# Windows 路径转 Linux 路径
win_path = "data\\spectra\\sample_001.csv"
linux_path = win_path.replace("\\", "/")
print(linux_path)  # data/spectra/sample_001.csv

# 或者用 os.path.normpath
normalized = os.path.normpath(win_path)
print(normalized)  # 根据当前系统转换
我的建议: 写代码时统一用正斜杠 /,Python 在 Windows 下也能识别。这样你的代码拿到任何系统上都能跑。

知识体系总览

下面这张图,是我自己整理的。它把文件批量读取和路径管理的核心逻辑串起来了:

文件批量读取与路径管理知识体系 文件批量读取 os 模块 glob 模块 路径处理 os.getcwd() / os.listdir() os.path.join() / os.path.exists() os.path.isfile() / os.path.isdir() glob.glob("*.csv") 递归查找 **/*.csv 结合正则过滤文件名 pathlib.Path 对象 跨平台分隔符处理 os.path.normpath() 核心目标:自动化构建文件路径列表 避免手动操作,提高效率,跨平台兼容

避坑指南

最后,分享几个我踩过的坑:

  • 路径中有空格: 我曾经有个文件夹叫"my data",结果脚本死活找不到文件。后来发现是路径没加引号。用os.path.join可以避免这个问题。
  • 隐藏文件: glob.glob("*")默认不匹配以点开头的隐藏文件。如果你需要,得用glob.glob(".*")单独处理。
  • 递归深度:**递归查找时,如果目录层级太深,可能会很慢。建议先print一下看看结果对不对,再继续处理。
  • 编码问题: 中文文件名在Windows下有时会乱码。我习惯在脚本开头加上# -*- coding: utf-8 -*-,然后用os.listdir时指定编码。
重要提醒: 批量操作文件前,一定要先备份!我见过太多人一个不小心把数据全删了。先打印出文件列表确认无误,再执行真正的操作。

好了,文件批量读取和路径管理这块,就聊到这儿。你把这些技巧用熟了,处理光谱数据的时候,能省下不少时间。