我的知识记录

Python批量从文件名提取日期建子目录归档教程

用Python正则从文件名中自动识别日期,按年/月/日创建子文件夹,把散落的文件自动归类到对应日期目录下,整理下载文件夹神器。

场景痛点

下载文件夹里堆了几百个文件,文件名里都带日期(比如 合同_2025-03-15.pdf报表20250320.xlsx),但全都平铺在一个目录里,找三个月前的文件得翻半天。想按年月分子文件夹整理,手动建目录、拖文件,几百个文件能拖到鼠标手。用Python正则识别文件名里的日期,自动建 2025/03/ 这种年月目录,把文件移进去,一键归档完成。

用到的库

pip install openpyxl

核心用标准库 osrepathlibshutil,日志用 openpyxl

完整代码

import re
import shutil
from pathlib import Path
from openpyxl import Workbook


def extract_date_from_name(filename: str):
"""
从文件名提取日期,支持常见格式:
2025-03-15、2025_03_15、20250315、2025.03.15
返回 (year, month, day) 或 None
"""
# 2025-03-15 / 2025_03_15 / 2025.03.15
m = re.search(r"(20\d{2})[-_.](\d{1,2})[-_.](\d{1,2})", filename)
if m:
y, mo, d = int(m.group(1)), int(m.group(2)), int(m.group(3))
if 1 <= mo <= 12 and 1 <= d <= 31:
return y, mo, d

# 20250315(8位连续数字)
m = re.search(r"(20\d{2})(\d{2})(\d{2})", filename)
if m:
y, mo, d = int(m.group(1)), int(m.group(2)), int(m.group(3))
if 1 <= mo <= 12 and 1 <= d <= 31:
return y, mo, d

return None


def archive_by_date(src_dir: str, dst_dir: str,
structure: str = "year_month"):
"""
把 src_dir 里带日期的文件移到 dst_dir 下按日期分的子目录。
structure:
"year_month"  ->  dst/2025/03/文件
"year_month_day" -> dst/2025/03/15/文件
"year"        ->  dst/2025/文件
"""
src = Path(src_dir)
dst = Path(dst_dir)
dst.mkdir(parents=True, exist_ok=True)

moved = []
skipped = []

for p in src.iterdir():
if not p.is_file():
continue
date_parts = extract_date_from_name(p.name)
if date_parts is None:
skipped.append((p.name, "未识别到日期"))
continue

y, mo, d = date_parts
if structure == "year_month":
target_dir = dst / str(y) / f"{mo:02d}"
elif structure == "year_month_day":
target_dir = dst / str(y) / f"{mo:02d}" / f"{d:02d}"
else:
target_dir = dst / str(y)

target_dir.mkdir(parents=True, exist_ok=True)
target_file = target_dir / p.name

# 重名加序号
i = 1
while target_file.exists():
target_file = target_dir / f"{p.stem}_{i}{p.suffix}"
i += 1

try:
shutil.move(str(p), str(target_file))
moved.append({"from": str(p), "to": str(target_file)})
print(f"{p.name} -> {target_file.relative_to(dst)}")
except OSError as e:
skipped.append((p.name, str(e)))

return moved, skipped


def export_log(moved: list, skipped: list, out_path: str):
wb = Workbook()
ws = wb.active
ws.title = "归档日志"
ws.append(["状态", "原路径", "新路径/原因"])
for m in moved:
ws.append(["成功", m["from"], m["to"]])
for name, reason in skipped:
ws.append(["跳过", name, reason])
ws.column_dimensions['A'].width = 10
ws.column_dimensions['B'].width = 60
ws.column_dimensions['C'].width = 60
wb.save(out_path)


if __name__ == "__main__":
SRC = r"C:\Users\hwwen\Downloads"
DST = r"D:\归档\按日期整理"

moved, skipped = archive_by_date(SRC, DST, structure="year_month")
print(f"\n归档完成:移动 {len(moved)} 个,跳过 {len(skipped)} 个")
export_log(moved, skipped, r"D:\归档\归档日志.xlsx")

代码讲解

extract_date_from_name 用正则做两轮匹配:第一轮找带分隔符的日期(横杠、下划线、点都兼容),第二轮找8位连续数字。找到后校验月份1-12、日期1-31,防止把别的8位数字(比如订单号20250315123)误当日期。archive_by_date 根据 structure 参数决定子目录深度:年/月两级、年/月/日三级、或只按年。mkdir(parents=True, exist_ok=True) 自动建多层目录,不存在就建,存在不报错。重名加序号,shutil.move 跨盘会自动处理(本质是复制+删除原文件)。

运行结果

控制台逐文件打印归档路径,最后 D:\归档\按日期整理\ 下生成 2025/03/2025/04/ 这样的年月子目录,对应日期的文件全在里面。同时生成 归档日志.xlsx,记录每个文件从哪移到哪,没识别出日期的文件列在跳过里,留在原目录手动处理。

注意事项

  • 脚本是移动不是复制,原目录文件会被移走,第一次跑先小范围测试。
  • 正则只匹配20开头的年份(2000-2099),19开头的老日期识别不到,需要的话把正则里的 20 改成 (19|20)
  • 文件名里有别的数字串可能干扰匹配,校验月日范围那一步能挡掉大部分误判。
  • 网盘目录里的文件移动后会触发重新上传,注意流量和同步冲突。
  • 想只归档不移动,把 shutil.move 换成 shutil.copy2 即可。

Python批量从文件名提取日期建子目录归档教程

标签:

更新时间:2026-09-14 21:20:19

上一篇:Python解压zip压缩包教程:一行代码完整提取

下一篇:Python批量提取压缩包密码列表教程