或是偷懒,或是相机直出的JPG已足够支持分享社交媒体的后期,旅行时往往直接用jpg修图,回家存入NAS的时候又舍不得RAW文件,30FPS下RAW文件可以说时拍了一堆,于是求助AI做了个简单的powershell命令行工具,以期从海量的RAW文件中提取那些对应已经精选过的jpg的原图。
需要exiftool这个牛逼工具的支持
受制于读卡速度,第3步比较慢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
$srcJpgDir = "Z:\XXXX\XXXX\XX"
$rawStorageDir = "F:\XXXX\XXXX"
$destDir = "D:\XXXX"
$rawExtension = "*.cr3"
if (!(Get-Command exiftool -ErrorAction SilentlyContinue)) { Write-Host "错误:未发现 exiftool,请将其加入环境变量或放在脚本同目录。" -ForegroundColor Red pause exit }
if (!(Test-Path $destDir)) { New-Item -Path $destDir -ItemType Directory | Out-Null Write-Host "已创建目标文件夹: $destDir" -ForegroundColor Gray }
Write-Host "`n[1/2] 正在扫描原始 RAW 目录并建立时间戳索引..." -ForegroundColor Cyan $rawIndex = @{} $rawFiles = Get-ChildItem -Path $rawStorageDir -Filter $rawExtension -Recurse
$totalRaw = $rawFiles.Count $count = 0
foreach ($file in $rawFiles) { $count++ $percent = [math]::Round(($count / $totalRaw) * 100) Write-Progress -Activity "建立 RAW 索引中" -Status "正在读取: $($file.Name)" -PercentComplete $percent $dt = & exiftool -s3 -DateTimeOriginal "$($file.FullName)" if ($dt) { if ($rawIndex.ContainsKey($dt)) { $rawIndex[$dt] += ,$file.FullName } else { $rawIndex[$dt] = @($file.FullName) } } }
Write-Host "[2/2] 正在比对 JPG 并在索引中查找匹配项..." -ForegroundColor Cyan $jpgFiles = Get-ChildItem -Path $srcJpgDir -Filter *.jpg
$totalJpg = $jpgFiles.Count $jCount = 0 $matchSuccess = 0
foreach ($jpg in $jpgFiles) { $jCount++ $jPercent = [math]::Round(($jCount / $totalJpg) * 100) Write-Progress -Activity "正在比对并复制文件" -Status "当前处理: $($jpg.Name)" -PercentComplete $jPercent $dtJpg = & exiftool -s3 -DateTimeOriginal "$($jpg.FullName)" if ($dtJpg -and $rawIndex.ContainsKey($dtJpg)) { foreach ($rawPath in $rawIndex[$dtJpg]) { $rawName = Split-Path $rawPath -Leaf Write-Host "[$jCount/$totalJpg] 命中! -> $rawName" -ForegroundColor Green Copy-Item -Path $rawPath -Destination $destDir -Force $matchSuccess++ } } else { Write-Host "[$jCount/$totalJpg] 未匹配: $($jpg.Name)" -ForegroundColor Gray } }
Write-Progress -Activity "正在比对并复制文件" -Completed Write-Host "`n===============================================" -ForegroundColor White Write-Host "任务完成!" -ForegroundColor Cyan Write-Host "共处理 JPG: $totalJpg 张" Write-Host "成功找回 RAW: $matchSuccess 份" Write-Host "输出目录: $destDir" Write-Host "===============================================" -ForegroundColor White Write-Host "按任意键退出..." $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
另外AI还提供了个极速版,思路是批量读取 (Batch Processing),不再逐个文件调用 exiftool,而是改为 JPG 扫一次,RAW 扫一次,避免进程反复启动: 减少上千次 exiftool.exe 启动的系统延迟。下次有机会再试下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| $srcJpgDir = "Z:\XXXX\XXXX\XXXX" $rawStorageDir = "F:\XXXX\XXXX" $destDir = "D:\XXXX" $rawExt = "cr3"
Write-Host "正在极速索引存储卡 (F:\)..." -ForegroundColor Cyan $rawIndex = @{}
$rawResults = & exiftool -r -ext $rawExt -s3 -p "`$Directory/`$FileName|`$DateTimeOriginal" "$rawStorageDir"
foreach ($line in $rawResults) { $parts = $line.Split('|') if ($parts.Count -eq 2) { $path = $parts[0]; $time = $parts[1] if ($rawIndex.ContainsKey($time)) { $rawIndex[$time] += ,$path } else { $rawIndex[$time] = @($path) } } }
Write-Host "正在极速索引导出目录 (Z:\)..." -ForegroundColor Cyan $jpgIndex = @{}
$jpgResults = & exiftool -ext jpg -s3 -p "`$Directory/`$FileName|`$DateTimeOriginal" "$srcJpgDir"
$matchCount = 0 foreach ($line in $jpgResults) { $parts = $line.Split('|') if ($parts.Count -eq 2) { $jpgPath = $parts[0]; $time = $parts[1] if ($rawIndex.ContainsKey($time)) { foreach ($rPath in $rawIndex[$time]) { $name = Split-Path $rPath -Leaf Write-Host "[命中] $time -> $name" -ForegroundColor Green Copy-Item -Path $rPath -Destination $destDir -Force -ErrorAction SilentlyContinue $matchCount++ } } } }
Write-Host "`n任务完成!成功找回 $matchCount 个文件。" -ForegroundColor Cyan
|