一种简陋但比较有效的图像去重方案。
动机
对于我这样经常从网络上保存各种图片的人来说,在归档时对图片进行去重是一个很常见的需求。
而图像去重,最简单的做法就是判断两个文件是否 完全一样。可以使用简单的摘要算法实现。
演化
最初开始做图片去重时,我用的是 Python 脚本的方式,实现起来非常简单,大概有以下几个步骤:
- 遍历指定目录下的文件,通过后缀名找到所有图片。
- 读取文件内容,计算 MD5 并生成新的文件名。
- 重命名文件。
这种方法实现起来非常容易,缺点是速度有些慢,但是对于日常使用来说是足够的。
后来我又在学习时写了一个 Rust 版本,借助第三方库实现了对文件的并行处理,速度快了很多。
但是今天我想要记录的重点并不是以上两种方案——我不得不承认,在我写下那个 Python 脚本的时候,我其实犯下了一个错误,我就像一个手里只有一把锤子的人,看什么问题都像钉子。
大概在这个方案使用了一年多以后,一次偶然的机会让我接触到了 Linux 系统中的 md5sum
工具,我才突然意识到自己之前的想法是多么狭隘——为什么我没有意识到这样常见的需求会有现存的工具可用呢?
解决
经过一番波折后,下面是我目前的最优解:
由于 macOS 并没有使用 md5sum
,而是用了另一个名为 md5
的工具——二者的输出格式有些不同,因此下面的脚本无法在 Linux 系统上运行,不过只需要对照 md5sum
的格式进行一点点更改就可以了。
1 | find . -type f -name "*.png" -exec md5 -r {} \; | awk '{print "mv \"" $2 "\" " $1".png"}' | sh |
简单解释一下这一行命令:
find . -type f -name "*.png"
- 这部分是在当前文件夹(
.
表示当前文件夹)及其子文件夹中寻找所有以“.png”结尾的文件(-type f
表示文件)。
- 这部分是在当前文件夹(
-exec md5 -r {} \;
- 对找到的每一个文件,执行
md5 -r
命令来计算其MD5值。{}
表示每一个找到的文件,\;
表示命令的结束。
- 对找到的每一个文件,执行
| awk '{print "mv \"" $2 "\" " $1".png"}'
- 计算出的MD5值和文件路径被传递给
awk
命令。awk
会生成一个新的命令:mv "原文件路径" "MD5值.png"
。意思是把原文件重命名为“MD5值.png”。
- 计算出的MD5值和文件路径被传递给
| sh
- 最后,这些生成的重命名命令通过管道传递给
shell
(sh
),并实际执行这些重命名操作。
- 最后,这些生成的重命名命令通过管道传递给