You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何按照片实际拍摄日期批量重命名文件夹中的JPG图片?

解决方法:获取照片EXIF拍摄日期来重命名

你的问题在于$_.CreationDate调用的是文件系统的创建时间(也就是文件被复制到当前文件夹的时间),而我们需要的是照片本身的EXIF拍摄日期——也就是Windows资源管理器「日期」列显示的数值(这个值优先读取照片的拍摄时间,没有的话才会 fallback 到文件时间)。

下面是两种可行的原生PowerShell实现方法,不需要额外安装工具:

方法1:利用Windows Shell属性读取拍摄日期

Windows资源管理器显示的「日期」其实对应Shell属性里的System.Photo.DateTaken,我们可以通过Shell.Application来获取这个属性值:

$shell = New-Object -ComObject Shell.Application

Get-ChildItem -Path "./" -Recurse -Include "*.jpg" | ForEach-Object {
    $folder = $shell.Namespace($_.DirectoryName)
    $file = $folder.ParseName($_.Name)
    # 获取拍摄日期属性(属性ID 12对应System.Photo.DateTaken)
    $dateTaken = $folder.GetDetailsOf($file, 12)
    
    if ($dateTaken) {
        # 将意大利语格式的日期转换为DateTime对象,再格式化为yyyyMMddHHmmss
        # 意大利语日期格式通常是dd/MM/yyyy HH:mm:ss,所以指定文化信息解析
        $dateObj = [DateTime]::Parse($dateTaken, [System.Globalization.CultureInfo]::GetCultureInfo("it-IT"))
        $newName = $dateObj.ToString("yyyyMMddHHmmss") + "_" + $_.Name.Replace("IMG", "")
        # 避免重名,添加序号
        $counter = 1
        $finalName = $newName
        while (Test-Path (Join-Path $_.DirectoryName $finalName)) {
            $finalName = $dateObj.ToString("yyyyMMddHHmmss") + "_$counter_" + $_.Name.Replace("IMG", "")
            $counter++
        }
        Rename-Item -Path $_.FullName -NewName $finalName -Force
    } else {
        # 如果没有拍摄日期, fallback 到文件创建时间
        $newName = $_.CreationDate.ToString("yyyyMMddHHmmss") + "_" + $_.Name.Replace("IMG", "")
        Rename-Item -Path $_.FullName -NewName $newName -Force
        Write-Warning "没有找到照片 $($_.Name) 的拍摄日期,使用文件创建日期重命名"
    }
}

代码说明:

  • Shell.Application获取文件夹和文件对象,通过属性ID 12获取拍摄日期(这个ID在Windows中是固定对应Date Taken的)
  • 因为你用的是意大利语Windows,所以解析日期时指定it-IT文化信息,确保能正确识别dd/MM/yyyy格式的日期
  • 添加了重名处理逻辑,避免同名文件覆盖
  • 如果照片没有EXIF拍摄日期,会自动 fallback 到原来的文件创建时间

方法2:直接读取EXIF元数据(需要PowerShell 5.1及以上)

另一种方法是直接读取图片的EXIF属性DateTimeOriginal,这是照片拍摄时相机记录的原始时间:

Get-ChildItem -Path "./" -Recurse -Include "*.jpg" | ForEach-Object {
    try {
        # 读取图片的EXIF元数据
        $image = [System.Drawing.Image]::FromFile($_.FullName)
        $dateTakenProp = $image.GetPropertyItem(36867) # 36867是DateTimeOriginal的EXIF标签ID
        $dateTakenStr = [System.Text.Encoding]::ASCII.GetString($dateTakenProp.Value).TrimEnd([char]0)
        
        # 将EXIF的日期格式(yyyy:MM:dd HH:mm:ss)转换为DateTime对象
        $dateObj = [DateTime]::ParseExact($dateTakenStr, "yyyy:MM:dd HH:mm:ss", $null)
        $newName = $dateObj.ToString("yyyyMMddHHmmss") + "_" + $_.Name.Replace("IMG", "")
        
        # 重名处理
        $counter = 1
        $finalName = $newName
        while (Test-Path (Join-Path $_.DirectoryName $finalName)) {
            $finalName = $dateObj.ToString("yyyyMMddHHmmss") + "_$counter_" + $_.Name.Replace("IMG", "")
            $counter++
        }
        
        Rename-Item -Path $_.FullName -NewName $finalName -Force
        $image.Dispose()
    } catch {
        # 读取EXIF失败时,使用文件创建时间
        $newName = $_.CreationDate.ToString("yyyyMMddHHmmss") + "_" + $_.Name.Replace("IMG", "")
        Rename-Item -Path $_.FullName -NewName $newName -Force
        Write-Warning "无法读取照片 $($_.Name) 的EXIF数据:$_,使用文件创建日期重命名"
    }
}

代码说明:

  • 直接通过System.Drawing.Image读取EXIF标签DateTimeOriginal(标签ID 36867)
  • 解析EXIF中固定格式的日期字符串yyyy:MM:dd HH:mm:ss,不需要考虑系统语言
  • 同样包含重名处理和 fallback 逻辑

注意事项:

  • 运行方法2时,可能需要以管理员权限启动PowerShell,避免权限不足无法读取图片文件
  • 对于经过编辑或无EXIF数据的照片,两种方法都会自动使用文件创建时间作为备选
  • 如果你想保留原文件名的部分内容,可以调整$newName的拼接逻辑,比如把$_.Name.Replace("IMG", "")改成你需要的格式

内容的提问来源于stack exchange,提问作者s_federici

火山引擎 最新活动