当前位置: 首页 > news >正文

Python脚本批量修复文件时间戳,根据文件名或拍摄日期

实现以下功能

  • 更正文件的 修改时间
  • 批量修改指定文件夹中的特定后缀的文件
  • 根据文件名中的日期修改(优先)
  • 根据 jpg 文件属性中的拍摄日期修改
  • 根据 mp4 文件属性中的创建媒体日期修改
  • 模拟运行(Dry Run)模式

依赖

若需要基于jpg文件属性中的拍摄日期修改,需要python的piexif

pip install piexif

若需要基于mp4文件属性中的创建媒体日期修改,需要ffmpeg

sudo apt install ffmpge

脚本仅在Linux上进行了测试,若在Windows上运行,可能还需要将ffmpeg的相关目录加入path。

代码

fix_timestamp.py

import os
import sys
import re
import piexif
import subprocess
from datetime import datetime, timezone, timedelta
from PIL import Image# 解析命令行参数
if len(sys.argv) < 2:print("[错误] 请提供文件夹路径作为参数。")print("示例: python fix_timestamp.py /home/user/media [--dry-run]")sys.exit(1)folder_path = sys.argv[1]
dry_run = "--dry-run" in sys.argv or "-n" in sys.argv# 要处理的文件后缀
valid_extensions = [".jpg", ".jpeg", ".png", ".mp4"]# 支持的时间格式正则表达式
time_patterns = [# 示例:Screenshot_2018-01-02-18-22-06-934_com.sina.weibo.jpg(r"(\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2})", "%Y-%m-%d-%H-%M-%S"),# 示例:IMG_20230517_094235.jpg(r"(\d{8}_\d{6})", "%Y%m%d_%H%M%S"),# 可以继续添加其他格式...
]def parse_time_from_filename(filename):"""尝试从文件名中解析时间"""for pattern, fmt in time_patterns:match = re.search(pattern, filename)if match:try:time_str = match.group(1)dt = datetime.strptime(time_str, fmt)return dtexcept ValueError:continuereturn Nonedef get_jpeg_exif_time(file_path):"""从 JPEG 的 EXIF 中获取拍摄时间(仅适用于 .jpg/.jpeg)"""try:with Image.open(file_path) as img:if "exif" in img.info:exif_dict = piexif.load(img.info["exif"])if piexif.ExifIFD.DateTimeOriginal in exif_dict["Exif"]:exif_time_str = exif_dict["Exif"][piexif.ExifIFD.DateTimeOriginal].decode("utf-8")try:dt = datetime.strptime(exif_time_str, "%Y:%m:%d %H:%M:%S")return dtexcept ValueError:print(f"[错误] EXIF时间格式错误: {exif_time_str}")except Exception as e:print(f"[异常] 读取EXIF出错: {e}")return Nonedef get_mp4_creation_time(file_path):"""使用 ffprobe 获取 MP4 的 creation_time 元数据"""cmd = ['ffprobe','-v', 'error','-show_entries', 'format_tags=creation_time','-of', 'default=nw=1',file_path]try:result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)output = result.stdout.strip()if output.startswith("TAG:creation_time="):dt_str = output.split("=", 1)[1]try:dt_utc = datetime.fromisoformat(dt_str.replace('Z', '+00:00'))tz_utc_8 = timezone(timedelta(hours=8))dt_local = dt_utc.astimezone(tz_utc_8)return dt_localexcept ValueError as ve:print(f"[解析错误] 时间格式不支持: {dt_str}, 错误: {ve}")except Exception as e:print(f"[异常] 获取视频时间失败: {e}")return None# 检查路径是否存在
if not os.path.isdir(folder_path):print(f"[错误] 路径不存在或不是文件夹: {folder_path}")sys.exit(1)print(f"[信息] 正在处理文件夹: {folder_path}")
if dry_run:print("[信息] 当前为 Dry Run 模式,不会修改任何文件。\n")# 遍历文件夹中所有指定后缀的文件
for filename in os.listdir(folder_path):ext = os.path.splitext(filename)[1].lower()file_path = os.path.join(folder_path, filename)print(f"\n[处理] 正在处理: {filename}")# 1. 尝试从文件名中提取时间dt = parse_time_from_filename(filename)if dt:print(f"[成功] 使用文件名中的时间: {dt.strftime('%Y:%m:%d %H:%M:%S')}")else:# 2. 如果是图片(.jpg/.jpeg),尝试从 EXIF 获取时间if ext in [".jpg", ".jpeg"]:dt = get_jpeg_exif_time(file_path)if dt:print(f"[成功] 使用EXIF中的拍摄时间: {dt.strftime('%Y:%m:%d %H:%M:%S')}")else:print(f"[跳过] 没有可用的EXIF拍摄时间。")# 3. 如果是视频(.mp4),尝试从 FFProbe 获取 creation_timeelif ext == ".mp4":dt = get_mp4_creation_time(file_path)if dt:print(f"[成功] 使用MP4中的创建时间: {dt.strftime('%Y:%m:%d %H:%M:%S')}")else:print(f"[跳过] 没有可用的creation_time元数据。")else:print(f"[跳过] 当前文件不支持获取时间信息。")# 如果获取到了时间,设置文件时间if dt:if dry_run:print(f"[DryRun] [模拟] 将设置文件时间为: {dt.strftime('%Y:%m:%d %H:%M:%S')}(不实际修改)")else:timestamp = dt.timestamp()os.utime(file_path, (timestamp, timestamp))print(f"[完成] 文件时间已更新为: {dt.strftime('%Y:%m:%d %H:%M:%S')}")else:print(f"[跳过] 无法获取时间信息: {filename}")print("\n>>>>> 运行结束 <<<<<")

运行示例

执行:

sudo python fix_timestamp.py /home/dlw/Media -n  # 模拟运行模式,去掉-n实际运行

输出:

[处理] 正在处理: 2848404867455998737608616768.mp4
[跳过] 没有可用的creation_time元数据。
[跳过] 无法获取时间信息: 2848404867455998737608616768.mp4[处理] 正在处理: 7695642187455636767332932782.mp4
[成功] 使用MP4中的创建时间: 2025:01:03 14:29:21
[DryRun] [模拟] 将设置文件时间为: 2025:01:03 14:29:21(不实际修改)[处理] 正在处理: IMG_20211201_235648_470_5.jpg
[成功] 使用文件名中的时间: 2021:12:01 23:56:48
[DryRun] [模拟] 将设置文件时间为: 2021:12:01 23:56:48(不实际修改)[处理] 正在处理: img-b1b1b00a1589edea0e7c74b235053cd4.jpg
[跳过] 没有可用的EXIF拍摄时间。
[跳过] 无法获取时间信息: img-b1b1b00a1589edea0e7c74b235053cd4.jpg[处理] 正在处理: -3cdc6e8e88e57e14.gif
[跳过] 当前文件不支持获取时间信息。
[跳过] 无法获取时间信息: -3cdc6e8e88e57e14.gif[处理] 正在处理: 3_d51.png
[跳过] 当前文件不支持获取时间信息。
[跳过] 无法获取时间信息: 3_d51.png[处理] 正在处理: IMG551013D.jpg
[成功] 使用EXIF中的拍摄时间: 2025:01:01 00:36:51
[DryRun] [模拟] 将设置文件时间为: 2025:01:01 00:36:51(不实际修改)>>>>> 运行结束 <<<<<
http://www.lryc.cn/news/590723.html

相关文章:

  • 达梦数据库CASE_SENSITIVE大小写敏感差异比较
  • 字段级权限控制场景中,RBAC与ABAC的性能差异
  • 【机器学习【6】】数据理解:数据导入、数据审查与数据可视化方法论
  • [NOIP][C++] 树的重心
  • 嵌入式单片机开发实战指南: 从RISC-V到TinyML全栈技术
  • 筑牢网络安全防线:DDoS/CC 攻击全链路防护技术解析
  • 权限隔离设计中实现字段级别的动态隐藏
  • 工作第一步建立连接——ssh
  • 【JavaScript】从事件流到事件委托
  • 再探多线程Ⅰ--- (创建思路+核心方法+代码样例)
  • [Mysql] Connector / C++ 使用
  • 二分查找算法(一)
  • 多目标优化|HKELM混合核极限学习机+NSGAII算法工艺参数优化、工程设计优化,四目标(最大化输出y1、最小化输出y2,y3,y4),Matlab完整源码
  • WP Force SSL Pro – HTTPS SSL Redirect Boost Your Website‘s Trust in Minutes!
  • 代码随想录算法训练营完结篇
  • 主流 TOP5 AI智能客服系统对比与推荐
  • Raydium CLMM 协议
  • Gradle vs Maven:构建工具世纪对决 —— 像乐高积木与标准模型之间的选择艺术
  • Transform的重要方法
  • excel分组展示业绩及增长率
  • 归一化与激活函数:深度学习的双引擎
  • 【WRFDA数据教程第一期】LITTLE_R 格式详细介绍
  • opencv 值类型 引用类型
  • 身份证号码姓名认证解决方案-身份证三要素API接口
  • Python+Selenium自动化
  • 【python】sys.executable、sys.argv、Path(__file__) 在PyInstaller打包前后的区别
  • Linux内核IPv4路由查找:LPC-Trie算法的深度实践
  • 门级网标仿真的时钟异常检查
  • 【C++高阶四】红黑树
  • ELK日志分析,涉及logstash、elasticsearch、kibana等多方面应用,必看!