从U盘损坏中恢复视频文件并修复修改日期的完整解决方案
问题背景
我的U盘突然损坏无法读取,使用DiskGenius成功恢复了所有视频文件,但遇到了一个奇怪的问题:
-
Windows文件管理器:显示正确的日期
-
macOS Finder:显示错误的日期(全部变成了修复当天的日期)
问题分析
经过深入调查,发现问题出在:
-
Windows和macOS处理文件元数据的方式不同
-
Windows文件管理器显示的"日期"列实际上是读取MP4文件内部的元数据
-
macOS Finder默认显示的是文件系统的修改日期
-
-
数据恢复工具的局限性
-
DiskGenius恢复文件时,文件系统的修改日期被重置为恢复当天
-
但MP4文件内部的创建媒体日期仍然保持正确
-
-
验证方法
-
在Windows中:右键文件 → 属性 → 详细信息 → 查看"媒体创建日期"
-
在macOS中:需要使用特殊工具才能看到文件内部的元数据
-
技术解决方案
Python脚本修复日期
通过编写Python脚本,直接从MP4文件内部读取正确的创建日期,并修复文件系统的修改日期:
# -*- coding: utf-8 -*-
"""
修复MP4视频文件的修改日期
从MP4文件内部的创建媒体日期读取正确的日期,并修复文件修改日期
"""import struct
import os
import sys
from datetime import datetime, timedeltadef get_mp4_creation_date(filename):"""从MP4文件中读取创建媒体日期MP4文件结构:- moov atom: 元数据容器- mvhd atom: 电影头,包含创建时间- 创建时间使用1904-01-01作为基准Args:filename: MP4文件路径Returns:datetime对象,如果未找到则返回None"""try:with open(filename, 'rb') as f:data = f.read()base_date = datetime(1904, 1, 1, 0, 0, 0) # MP4时间基准# 解析atom结构i = 0while i < len(data) - 8:try:size = struct.unpack('>I', data[i:i+4])[0]if size == 0 or size > len(data) - i or size < 8:breakatom_type = data[i+4:i+8]# 查找moov atomif atom_type == b'moov':# 在moov内查找mvhd atomj = i + 8while j < i + size - 8:try:sub_size = struct.unpack('>I', data[j:j+4])[0]if sub_size == 0 or sub_size > size:breaksub_type = data[j+4:j+8]if sub_type == b'mvhd':version = data[j+8]# 版本0: 使用32位时间戳if version == 0 and sub_size >= 24:creation_time = struct.unpack('>I', data[j+12:j+16])[0]creation_dt = base_date + timedelta(seconds=creation_time)return creation_dt# 版本1: 使用64位时间戳elif version == 1 and sub_size >= 32:creation_time = struct.unpack('>Q', data[j+12:j+20])[0]creation_dt = base_date + timedelta(seconds=creation_time)return creation_dtj += sub_sizeexcept:j += 1if j >= i + size - 8:breaki += sizeexcept:i += 1if i >= len(data) - 8:breakreturn Noneexcept Exception as e:print(f"读取文件 {filename} 时出错: {e}")return Nonedef fix_file_date(filename, creation_date):"""使用创建媒体日期修复文件修改日期Args:filename: 文件路径creation_date: datetime对象Returns:bool: 是否成功"""try:import subprocess# macOS使用SetFile命令设置日期date_str = creation_date.strftime('%m/%d/%Y %H:%M:%S')result = subprocess.run(['SetFile', '-d', date_str, '-m', date_str, filename], capture_output=True, text=True)if result.returncode == 0:return Trueelse:# 如果SetFile失败,尝试使用touch命令date_str_touch = creation_date.strftime('%Y%m%d%H%M.%S')subprocess.run(['touch', '-t', date_str_touch, filename], check=True)return Trueexcept Exception as e:print(f"设置日期失败: {e}")return Falsedef main():"""主函数:批量处理MP4文件"""if len(sys.argv) < 2:print("用法: python3 fix_mp4_date.py <目录或文件>")sys.exit(1)target = sys.argv[1]# 获取文件列表if os.path.isfile(target):files = [target]elif os.path.isdir(target):files = [os.path.join(target, f) for f in os.listdir(target) if f.endswith('.mp4') and not f.startswith('._')]else:print(f"错误: {target} 不是有效的文件或目录")sys.exit(1)files.sort()print(f"找到 {len(files)} 个MP4文件,开始处理...\n")success_count = 0failed_count = 0for file_path in files:print(f"处理: {os.path.basename(file_path)}")creation_date = get_mp4_creation_date(file_path)if creation_date:print(f" 创建媒体日期: {creation_date.strftime('%Y-%m-%d %H:%M:%S')}")if fix_file_date(file_path, creation_date):print(f" ✓ 日期修复成功")success_count += 1else:print(f" ✗ 日期修复失败")failed_count += 1else:print(f" ✗ 未找到创建媒体日期")failed_count += 1print()print(f"处理完成: 成功 {success_count}, 失败 {failed_count}, 总计 {len(files)}")if __name__ == '__main__':main()
技术细节解析
MP4文件结构
MP4文件使用"atom"(也称为"box")结构存储数据:
-
ftyp:文件类型标识 -
moov:元数据容器(包含视频时长、创建时间等信息) -
mdat:媒体数据(实际的音视频数据)
时间处理
-
MP4使用1904-01-01作为时间基准(不是Unix的1970-01-01)
-
时间戳存储为相对于1904-01-01的秒数
-
需要将读取到的时间戳转换为正常的日期时间格式
跨平台兼容性
-
Windows:直接读取MP4内部元数据显示日期
-
macOS:默认显示文件系统修改日期,需要特殊处理
-
脚本使用macOS的
SetFile和touch命令来修改文件日期
经验总结
-
数据恢复后的常见问题:文件系统元数据丢失,但文件内部元数据通常完好
-
操作系统差异:
-
Windows和macOS处理文件元数据的方式不同
-
不能仅凭Finder显示判断文件日期是否正确
-
-
解决方案验证:
-
使用专业工具(如exiftool)验证文件内部元数据
-
在不同操作系统中对比验证
-
-
批量处理效率:
-
对于大量文件,使用脚本批量处理
-
先在小样本上测试,确认无误后再处理全部文件
-
结语
通过这个Python脚本,成功解决了从损坏U盘恢复视频文件后日期显示错误的问题。关键在于理解不同操作系统处理文件元数据的差异,并直接从MP4文件内部读取正确的创建日期来修复文件系统日期。
这个方法不仅适用于数据恢复场景,也适用于任何需要批量修复MP4文件日期的需求。希望这个解决方案能帮助到遇到类似问题的朋友!
