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.pswp.cn/pingmian/89145.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89145.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Mysql] Connector / C++ 使用

一、Connector / C 使用 要使用 C 语言连接 MySQL&#xff0c;需要使用 MySQL 官网提供的库&#xff0c;可以去官网进行下载&#xff1a;MySQL :: MySQL Community Downloads 我们使用 C 接口库来进行连接&#xff0c;要正确使用&#xff0c;还需要做一些准备工作&#xff1a…

【PDF识别改名】使用京东云OCR完成PDF图片识别改名,根据PDF图片内容批量改名详细步骤和解决方案

京东云OCR识别PDF图片并批量改名解决方案一、应用场景在日常办公和文档管理中&#xff0c;经常会遇到大量 PDF 文件需要根据内容进行分类和命名的情况。例如&#xff1a;企业合同管理系统需要根据合同编号、日期等内容自动命名 PDF 文件图书馆数字化项目需要将扫描的图书章节按…

stm32-modbus-rs485程序移植过程

背景 【modbus学习笔记】Modbus协议解析_modus协议中0.001如何解析-CSDN博客 【Modbus学习笔记】stm32实现Modbus(从机)并移植_stm32 modbus数据处理-CSDN博客 继上篇成功移植modbus从机例程之后&#xff0c;我要尝试移植主机的程序。经提醒&#xff0c;可用野火的modbus代码…

Spring MVC 执行流程详解:一次请求经历了什么?

Spring MVC 执行流程详解&#xff1a;一次请求经历了什么&#xff1f; 引言 在现代 Web 开发中&#xff0c;Spring MVC 作为 Spring 框架的重要组成部分&#xff0c;广泛应用于构建灵活、可扩展的 Java Web 应用。作为一个基于 MVC&#xff08;Model-View-Controller&#xff0…

Vue 3的核心机制-解析事件流、DOM更新、数据请求、DOM操作规范及组件库DOM操作的解决方案

文章目录概要整体介绍vue 中dom操作推荐方案实例概要 从Vue 3的核心机制出发&#xff0c;结合场景、应用与实例&#xff0c;系统化解析事件流、DOM更新、数据请求、DOM操作规范及组件库DOM操作的解决方案&#xff1a; 整体介绍 ⚡️ 一、事件流处理机制 核心机制 • 三个阶段…

Python从入门到高手9.2节-Python字典的操作方法

目录 9.2.1 字典的操作 9.2.2 字典的查找 9.2.3 字典的修改 9.2.4 字典的添加 9.2.5 字典的删除 9.2.6 今天你逛街了吗 9.2.1 字典的操作 字典类型是一种抽象数据类型&#xff0c;抽象数据类型定义了数据类型的操作方法&#xff0c;在本节的内容中&#xff0c;教同学们彻…

omniparser v2 本地部署及制作docker镜像(20250715)

关于 omniparser v2 本地部署&#xff0c;网上资料不算多&#xff0c;尤其是对于土蔷内用户&#xff0c;还是有些坑的。 1、安装步骤 可参考两个CSDN博客&#xff1a; &#xff08;1&#xff09;大模型实战 - ‘OmniParser-V2本地部署安装 链接 &#xff08;2&#xff09;…

自己写个 `rsync` + `fswatch` 实时增量同步脚本,干掉 Cursor AI、Sublime Text 的SFTP等 插件!

自己写个 rsync fswatch 实时增量同步脚本&#xff0c;干掉 Cursor AI、Sublime Text 的 SFTP等 插件&#xff01; 作为一个码农&#xff0c;我最头疼的事情之一就是编辑器同步代码到服务器这块。用过各种各样的sftp、rsync插件&#xff0c;感觉不好用。。 我琢磨着&#xff1…

linux中at命令的常用用法。

Linux 中 at 命令用于安排一次性定时任务&#xff0c;需要用到在某个时间只需要执行一次的命令的时候&#xff0c;可以使用at 1&#xff1a;安装at # Debian/Ubuntu sudo apt install at# CentOS/RHEL sudo yum install at2&#xff1a;启动at sudo systemctl start atd # 启…

【安卓笔记】RxJava的使用+修改功能+搭配retrofit+RxView防快速点击

0. 环境&#xff1a; 电脑&#xff1a;Windows10 Android Studio: 2024.3.2 编程语言: Java Gradle version&#xff1a;8.11.1 Compile Sdk Version&#xff1a;35 Java 版本&#xff1a;Java11 1. 介绍RxJava GitHub开源地址&#xff1a;https://github.com/Reactive…

Windows 下原生使用 claude code + Kimi K2

搞定了kimi k2 claude code在windows下原生使用 Windows下使用claude code的障碍是shell环境&#xff08;命令行&#xff09;&#xff0c;非posix风格shell无法正常让claude code读取到url和key, 导致无法使用。解决问题的本质是使用符合posix风格的shell环境&#xff0c;我们…

Leetcode Easy题小解(C++语言描述)1

Leetcode Easy题小解&#xff08;C语言描述&#xff09; 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交**&#xff1a;**题目数据…

EP01:【NLP 第二弹】自然语言处理概述

一、NLP通向智能之路 1.1 图灵测试 1.1.1 提出背景 由计算机科学家阿兰・图灵于 1950 年提出&#xff0c;是早期衡量机器智能水平的重要概念。 1.1.2 提出目的 判断机器是否能表现出与人类相当的智能行为。 1.1.3 测试原理 场景设定&#xff1a;测试中存在一位人类测试者&#…

Ansible 查看PostgreSQL的版本

Ansible的基础知识就不说了直接贴剧本- name: Check PostgreSQL versionhosts: db_serversbecome: yesvars:ansible_python_interpreter: /usr/bin/python3db_name: postgresdb_user: postgresdb_password: your_passwordtasks:- name: Install psycopg2ansible.builtin.packag…

【视觉SLAM笔记】第9章 后端1

一、理论1. 状态估计的概率解释我们来深入探讨一下视觉SLAM中状态估计的概率解释。这可以说是理解现代SLAM算法&#xff08;尤其是后端优化&#xff09;的基石1. 问题的核心&#xff1a;不确定性SLAM&#xff08;同步定位与建图&#xff09;的本质是在一个未知环境中&#xff0…

(数据结构)复杂度

基本概念说明 数据结构 定义&#xff1a;数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在⼀种或多种特定关系的数据元素的集合。没有⼀种单⼀的数据结构对所有用途都有用&#xff08;要考虑适配、效率问题&#xff0c;在不同情况下使用合适的…

玩转Docker | 使用Docker部署bender个人导航页工具

玩转Docker | 使用Docker部署bender个人导航页工具 前言 一、bender介绍 Bender 简介 Bender 的主要特点 二、系统要求 环境要求 环境检查 Docker版本检查 检查操作系统版本 三、部署bender服务 下载bender镜像 编辑部署文件 创建容器 检查容器状态 检查服务端口 安全设置 四、…

解决了困扰我的upload靶场无法解析phtml等后缀的问题

本文章为解决困扰我的 upload 靶场无法解析 phtml 问题 ​ 这个问题直接让我过不了Upload-Pass-03这一关&#xff0c;一直卡着。 ​ 痛太痛了 &#xff0c;为什么无法解析上传之后的 phtml 后缀文件&#xff01;这块儿折磨了博主一天多&#xff0c;太不容易了&#xff0c;查找…

Leetcode百题斩-二分搜索

二分搜索也是一个很有趣的专题&#xff0c;被做过的题中&#xff0c;刚好一个Easy&#xff0c;一个Medium和一个Hard&#xff0c;刚好可以看看&#xff0c;二分搜索的三个难度等级都是啥样的。 124. Binary Tree Maximum Path Sum[Hard]&#xff08;详见二叉树专题&#xff09;…

【IDEA】格式化代码工具配置

格式化代码快捷键&#xff1a; CtrlAltL格式代码的时候不会再方法名与参数中间添加空格默认不勾选的情况下&#xff1a;代码样例&#xff1a;勾选之后的样例&#xff1a;选择不勾选&#xff0c;IDEA默认情况下就是不勾选的状态忽略加载文件有些非必要加载到开发工具中的文件我们…