问题背景
我的U盘突然损坏无法读取,使用DiskGenius成功恢复了所有视频文件,但遇到了一个奇怪的问题:
-
Windows文件管理器:显示正确的日期
-
macOS Finder:显示错误的日期(全部变成了修复当天的日期)
问题分析
经过深入调查,发现问题出在:
-
Windows和macOS处理文件元数据的方式不同
-
Windows文件管理器显示的"日期"列实际上是读取MP4文件内部的元数据
-
macOS Finder默认显示的是文件系统的修改日期
-
-
数据恢复工具的局限性
-
DiskGenius恢复文件时,文件系统的修改日期被重置为恢复当天
-
但MP4文件内部的创建媒体日期仍然保持正确
-
-
验证方法
-
在Windows中:右键文件 → 属性 → 详细信息 → 查看"媒体创建日期"
-
在macOS中:需要使用特殊工具才能看到文件内部的元数据
-
技术解决方案
Python脚本修复日期
通过编写Python脚本,直接从MP4文件内部读取正确的创建日期,并修复文件系统的修改日期:
python
# -*- coding: utf-8 -*-
"""
修复MP4视频文件的修改日期
从MP4文件内部的创建媒体日期读取正确的日期,并修复文件修改日期
"""
import struct
import os
import sys
from datetime import datetime, timedelta
def 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 = 0
while 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:
break
atom_type = data[i+4:i+8]
# 查找moov atom
if atom_type == b'moov':
# 在moov内查找mvhd atom
j = i + 8
while j < i + size - 8:
try:
sub_size = struct.unpack('>I', data[j:j+4])[0]
if sub_size == 0 or sub_size > size:
break
sub_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_dt
j += sub_size
except:
j += 1
if j >= i + size - 8:
break
i += size
except:
i += 1
if i >= len(data) - 8:
break
return None
except Exception as e:
print(f"读取文件 {filename} 时出错: {e}")
return None
def 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 True
else:
# 如果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 True
except Exception as e:
print(f"设置日期失败: {e}")
return False
def 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 = 0
failed_count = 0
for 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 += 1
else:
print(f" ✗ 日期修复失败")
failed_count += 1
else:
print(f" ✗ 未找到创建媒体日期")
failed_count += 1
print()
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文件日期的需求。希望这个解决方案能帮助到遇到类似问题的朋友!