miércoles, 19 de diciembre de 2012

Es guay utilizar algoritmos de digest II

En la entrada anterior se habló de como utilizar las funciones hash para proteger un poco más nuestros datos. En esta entrada estaremos utilizando las funciones hash para conseguir los archivos duplicados dentro de nuestro sistema.

El tema de esta entrada es simple, la temática es la siguiente: Se calcula el hash de los datos en este caso de cada archivo y se está pendiente de que dos archivos no tengan la misma función hash, de ser así, se tiene un archivo duplicado y se procede con el procesamiento deseado.

Para ejecutar el siguiente programa se necesita:
  • Ruby
  • La gema Mp3Info
    gem install mp3info 
#!/usr/bin/env ruby
# encoding: utf-8
# Program that looks for duplicate files.
# Author: MaG, http://newbieshell.blogspot.com

require 'digest/sha2'
require 'find'
require 'mp3info'

class FileRecord
     attr_reader :file, :sum, :duplicates
     def initialize(path, sum)
          @file = path
          @sum = sum
          @duplicates = []
     end

     def has_duplicates?
          not @duplicates.empty?
     end

     def add(path)
          @duplicates.push path
     end
end

if ARGV[0].nil? or not File.directory? ARGV[0]
     $stderr.puts "Use: #$0 <directory>"
     exit 1
end

hsh = {}
EMPTY_STRING_SUM = Digest::SHA256.hexdigest ''

Find.find(ARGV[0]) do|path|
     next unless File.file? path

     puts path

     sum = nil
     if path =~ /\.mp3$/i
          begin
               mp3 = Mp3Info.new(path)
               pos, length = mp3.audio_content
               mp3.close
          rescue
               next # discard this problematic file
          end

          File.open(path) do|file|
               file.pos = pos
               sum = Digest::SHA256.hexdigest(file.read(length))
          end
     else
          sum = Digest::SHA256.file(path).hexdigest
     end

     next if sum == EMPTY_STRING_SUM

     # nah!, let's use +unless+
     unless hsh[sum]
          hsh[sum] = FileRecord.new(path, sum)
     else
          file_record = hsh[sum]
          file_record.add(path)
     end
end

print "\n\nduplicates!\n\n"

hsh.each_value do|record|
     next unless record.has_duplicates?

     print "#{record.file}:\n->"
     print record.duplicates.join("\n-> "), "\n\n"
end
Se utiliza la gema Mp3Info para localizar el segmento de audio y calcular la función hash a dicha parte del archivo. Se hace esto, porque es posible que los metadatos de dos archivos varíen y de esta manera corrompan la singularidad del archivo, aun cuando dichos archivos contengan el mismo audio.

Si bien, el programa utiliza un buen algoritmo, este requiere una cantidad considerable de cálculos, los cuales son directamente proporcionales al tamaño de los archivos dentro del directorio raíz en cuestión. Pero algo si es seguro, encuentra los archivos duplicados.

Conclusión
Es posible implementar este programa en un Shell Script utilizando la herramienta sha256sum y el comando find. Aunque con el Shell será un poco más difícil contrarrestar el problema de los metadatos en los archivos de tipo: mp3, jpeg, png, pdf, etc.

Al parecer, los formatos de audio parecen ser los más propensos a este tipo de casos, donde los metadatos corrompen la función hash. Es muy importante tener esto pendiente para cuando se necesite un poco más de precisión.

Si necesitas una solución utilizando Bash, o necesitas ayuda, deja un comentario o contáctame por correo, el cual está en la parte de arriba de este blog.

No hay comentarios:

Publicar un comentario