关于本文
本文结合了生成式 AI 的辅助,并基于在 Windows PowerShell 5.1 上的实际测试结果整理而成。这不是纸上谈兵的示例,而是在使用 Google Takeout 真实数据并修复报错的过程中验证过的脚本。验证状态:✅ 已在 Windows PowerShell 5.1 真机上验证通过
已成功检测到 2645 张图片、104 个视频,共计 2749 个文件、15.81 GB,并确认修正版 v4 的复制处理与进度显示功能运行正常。
使用 Google Takeout 备份照片时,里面会混杂着 ZIP 压缩包、已解压的文件夹、JSON 文件等,有时我们事后会希望能“把照片和视频单独收集到一个地方”。
虽然也可以手动完成,但如果有数千个文件,光是检查就够让人头疼了。
因此,这次我们制作了一个 PowerShell 脚本,能够:自动将图片收集到 OutImages,视频收集到 OutVideos。
它的核心亮点在于,不仅是简单地复制,还能:显示还剩多少个文件、已经处理了多少 GB、以及预计剩余时间。即便在处理大视频的过程中,也能避免让人觉得“是不是卡死了”。
首先,如何使用
我们尽量简化了使用方法。
将本脚本放置在存放 Google Takeout 的 ZIP 压缩包或已解压文件夹的目录中。
GoogleTakeout ├─ takeout-001.zip ├─ takeout-002.zip ├─ takeout-003 │ └─ Takeout │ └─ Google フォト └─ Collect-GoogleTakeoutMedia-v4-beginner.ps1
在该文件夹中打开 PowerShell,然后运行以下命令。
.Collect-GoogleTakeoutMedia-v4-beginner.ps1
基本操作就是这样。
运行后,会自动创建一个 Out 文件夹。
GoogleTakeout
├─ takeout-001.zip
├─ takeout-002.zip
├─ takeout-003
├─ Collect-GoogleTakeoutMedia-v4-beginner.ps1
│
└─ Out
├─ Images ← 写真・画像
├─ Videos ← 動画
└─ media-copy-YYYYMMDD-HHMMSS.log
↑ エラーなどの記録
处理过程大致分为三个阶段
在看代码之前,只要了解处理流程就足够了。
flowchart TD
A[Google Takeoutのフォルダー] --> B[STEP 1 普通のフォルダーを調べる]
B --> C[STEP 2 ZIPの中を調べる]
C --> D[画像・動画の全件数と容量を集計]
D --> E[STEP 3 Outへコピー]
E --> F[Images]
E --> G[Videos]
E --> H[ログ]
步骤 1:检查普通文件夹
首先,依次检查已解压的 Google Takeout 文件夹。
此时还不会进行复制。
.jpg、.png、.heic 等会被记录为图片,.mp4、.mov 等会被记录为视频,并在列表中登记。Google Takeout 自带的 JSON 等文件不在处理范围内。
原理很简单,就是查看文件名末尾的“扩展名”。
$ImageExtensions = @(
'.jpg','.jpeg','.png','.gif','.bmp','.tif','.tiff','.webp',
'.heic','.heif','.avif'
)
$VideoExtensions = @(
'.mp4','.mov','.m4v','.avi','.mkv','.webm',
'.3gp','.mts','.m2ts','.mpg','.mpeg','.wmv'
)
对初学者来说,这就相当于预先制作好了:“作为图片处理的扩展名列表”和“作为视频处理的扩展名列表”。
步骤 2:不解压整个 ZIP,只查看其内容
Google Takeout 的内容有时会保留为 ZIP 压缩包的形式。
在本脚本中,不是将 ZIP 全部解压后再搜索,而是通过 PowerShell 利用 .NET 的 ZIP 功能直接查看内部文件。
Add-Type -AssemblyName System.IO.Compression.FileSystem $archive = [System.IO.Compression.ZipFile]::OpenRead($zipPath)
然后,如果 ZIP 中包含图片或视频,稍后只提取需要的部分。
这样一来,就可以减少完整解压 ZIP 所需的额外磁盘空间。
此外,如果像
takeout-001.zip takeout-001
那样,ZIP 文件和与其同名的已解压文件夹同时存在,则会跳过 ZIP 文件。这是为了避免重复收集相同的照片。
预先统计总文件数
搜索结束后,在实际复制之前会显示总体概况。
在本次真机测试中,得到了以下结果。
--- 検索結果 --- 画像 : 2,645 件 動画 : 104 件 合計 : 2,749 件 / 15.81 GB
有了这个,就不用面对“不知道还有几千个文件”的未知等待,而是能:在一开始就知道目标有多大。
步骤 3:复制到 Out 文件夹
接下来就是实际的复制操作了。
如果是图片,保存到:
OutImages
如果是视频,保存到:
OutVideos
。
不过,脚本不会一口气复制大视频,而是以 4 MiB 为单位进行读写。
$buffer = New-Object byte[] 4194304
while (($read = $InputStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
$outStream.Write($buffer, 0, $read)
$script:ProcessedBytes += $read
Show-CopyProgress -CurrentName $DisplayName
}
这就是防止“看起来像卡死”的关键所在。
即使在处理大文件的过程中,已处理的容量也会不断增加,从而能够实时更新进度。
显示“还要多久?”
在复制过程中,会显示类似以下的信息。
1200/2749 完了 残り 1549 件 6.8 GB / 15.81 GB 残り目安 18分
不仅仅是单纯的“已完成 1200 个文件”。
图片可能只有几 MB,而视频可能有几 GB。因此:脚本不仅根据文件数量,还会根据已处理的数据量来估算剩余时间。
这种思路即使在处理大量文件的日常办公中也非常实用。
复制中的文件会带上 .part 后缀
出于安全考虑引入的设计是 .part。
例如在复制视频时,不会直接创建最终的
movie.mp4
文件。
而是首先作为
movie.mp4.part
进行复制。
只有在顺利复制到最后之后,才会更改为
movie.mp4
。
$partPath = $Destination + '.part' # コピー処理 # ... Move-Item -LiteralPath $partPath -Destination $Destination -Force
这是为了防止中途停止的视频被误认为是完整的视频。
原始的 Google Takeout 数据不会被删除。
即使有同名照片也不会覆盖
不同文件夹中可能存在同名的 IMG_0001.JPG 文件。
如果文件名和大小相同,则认为已经复制过并予以跳过。
如果文件名相同但大小不同,则会像
IMG_0001__a1b2c3d4.JPG
那样附加简短的识别字符,作为独立文件保存。
在“无论如何都要收集到一个文件夹中”的任务里,不进行覆盖是非常重要的。
实际运行后,在 15GB 时遇到了报错
这是只有在实际运行后才能发现的部分。
在最初的版本中,由于使用 15.81 GB 的总容量来计算剩余容量,导致 Windows PowerShell 5.1 报了以下错误。
Int32 型の値が大きすぎるか、または小さすぎます。
原因在于试图将庞大的字节数当作 32 位整数来处理。
因此,在修正版中,容量被明确作为 64 位整数 [long] 来处理。
[long]$remainingBytes = $script:TotalBytes - $script:ProcessedBytes
if ($remainingBytes -lt 0) {
$remainingBytes = 0L
}
这一点在小型示例数据中是很难察觉的。
处理几 GB 时运行正常,但在处理 15 GB 的真实数据时才会崩溃。
本文中“实际尝试的价值”最大的地方,可能就在于此。
无需完全理解代码即可使用
对于 PowerShell 初学者来说,可能会看到 FileStream、ArrayList、ZipFile 等生疏的词汇。
但一开始并不需要全部理解。
本次提供的完整版脚本将处理过程分为以下 8 个部分,并添加了中文注释。
初始设置
判断是照片还是视频的准备工作
记录进度的数字变量
复制单个文件的组件
步骤 1:检查文件夹
步骤 2:检查 ZIP 文件
步骤 3:实际执行复制
最后显示结果
首先,
置く ↓ 実行する ↓ 中を調べる ↓ 件数を数える ↓ Outへコピーする ↓ 結果を見る
只要明白这个流程就足够了。
如果不希望检查 ZIP 文件
如果只想处理已解压的文件夹,可以加上 -NoZip 参数。
.Collect-GoogleTakeoutMedia-v4-beginner.ps1 -NoZip
也可以指定其他路径。
.Collect-GoogleTakeoutMedia-v4-beginner.ps1 `
-SourceRoot "D:GoogleTakeout"
总结
这次想做的事情,从技术上讲是“递归搜索”、“ZIP 读取”和“流复制”,但对使用者而言要简单得多。
只想把 Google Takeout 里的照片和视频收集起来。想知道处理有没有卡住。想知道还要多久才能完成。
为此,我们逐步向 PowerShell 中添加了所需的功能。
通过这次使用 2749 个文件、15.81 GB 的真实数据进行测试,我们甚至发现了 PowerShell 5.1 的大数值整数错误,并在修正版 v4 中确认了运行正常。
不仅止步于“编写代码”,用真实数据运行、修复出现的错误、将其打造成初学者也能使用的形态,这整个过程才算是一个完整的示例。
