2
2

More than 3 years have passed since last update.

【Kotlin】内容の重複したファイルを削除する【Java】

Last updated at Posted at 2020-05-21

やりたいこと

あるディレクトリの中に内容の重複したファイルが大量に有る時、1つだけ残して重複したものを削除します。

やり方

ファイル全体を比較すると処理コストが高くて大変です。

そこで今回はファイルのハッシュ(ダイジェスト)を比較することとし、以下の方針で実装しました。

  1. ファイルのハッシュを取ってダイジェストを取得
  2. ダイジェストがSetに既存かチェック
  3. 存在していれば削除
  4. 存在していなければSetadd

サンプルコード

とりあえず動くサンプルは以下の通りです。

import java.io.File
import java.security.MessageDigest

val sha256 : MessageDigest = MessageDigest.getInstance("SHA-256")

fun getDigest(bytes: ByteArray): List<Byte> = sha256.digest(bytes).asList()

fun getFiles(pathToDir: String): List<File> = File(pathToDir).listFiles()?.asList() ?: emptyList()

fun main() {
    val files = getFiles(/* 処理対象ディレクトリのパス */)

    val set = HashSet<List<Byte>>()
    var count = 0

    files.forEach {
        val digest = getDigest(it.readBytes())

        if (!set.add(digest)) {
            if (it.delete()) {
                println("Deleted:\t${it.name}")
                count++
            } else {
                println("Fail delete:\t${it.name}")
            }
        }
    }

    println("\n\n$count deleted.")
}

実行結果

折り畳み
Deleted:    43_3のコピー.gif
Deleted:    46_3のコピー2.gif
Deleted:    70_1のコピー2.gif
Deleted:    94_1のコピー.gif
Deleted:    50_3のコピー2.gif
Deleted:    66_1のコピー.gif
Deleted:    95_1のコピー.jpg
Deleted:    58_3のコピー.gif
Deleted:    63_1のコピー.gif
Deleted:    32_1のコピー.jpg
Deleted:    55_3のコピー.gif
Deleted:    62_3のコピー.gif
Deleted:    49_3のコピー.gif
Deleted:    9_1のコピー2.gif
Deleted:    47_3のコピー.gif
Deleted:    96_1のコピー.jpg
Deleted:    71_1のコピー.gif
Deleted:    52_3のコピー2.gif
Deleted:    64_1のコピー2.gif
Deleted:    61_3のコピー.gif
Deleted:    56_3のコピー.gif
Deleted:    60_3のコピー2.gif
Deleted:    31_1のコピー.jpg
Deleted:    57_3のコピー2.gif
Deleted:    98_1のコピー2.jpg
Deleted:    34_1のコピー.jpg
Deleted:    68_1のコピー.gif
Deleted:    53_3のコピー.gif
Deleted:    42_3のコピー.gif
Deleted:    74_1のコピー2.gif
Deleted:    30_1のコピー.gif
Deleted:    36_1のコピー2.gif
Deleted:    65_1のコピー.gif
Deleted:    100_1のコピー.jpg
Deleted:    37_1のコピー.gif
Deleted:    35_1のコピー2.gif
Deleted:    45_3のコピー.gif
Deleted:    99_1のコピー.jpg
Deleted:    87_1のコピー2.jpg
Deleted:    33_1のコピー.jpg
Deleted:    73_1のコピー.gif
Deleted:    1_7のコピー.jpg
Deleted:    48_3のコピー.gif
Deleted:    54_3のコピー2.gif
Deleted:    51_3のコピー.gif
Deleted:    67_1のコピー.gif
Deleted:    93_1のコピー2.gif
Deleted:    44_3のコピー2.gif
Deleted:    72_1のコピー2.gif
Deleted:    97_1のコピー2.jpg


50 deleted.

解説

ハッシュの取り方

java.security.MessageDigestを利用しました。
これは特にライブラリ等を導入せずJava標準で使えます。

今回はテキトーにSHA-256を指定しましたが、「極限まで重複を回避したいぜ!」という場合はSHA-512を指定してあげればいいと思います。

重複管理

恐らくHashSetを使うのが一番簡単かつコストも低いと思います。
また、ByteArrayではequals周りに不安があるため、ここではListに変換して取り扱っています。

2
2
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2