RubyにおけるMIME型判別ライブラリの比較

Rubyでファイルに対するMIME型の自動判別を行うには、次のライブラリが便利です。

これらの違いは判別方法にあります。MIME::Typesは、IANAに登録されているMIME型情報を元に、ファイルの拡張子から判別を行なうので、拡張子が付いていないものに対しては無力です。一方shared-mime-infoは、freedesktop.orgの提供するMIMEデータベースを使い、拡張子とファイル内容の両面から判別することが出来ます。よって、拡張子が付いているとは限らない環境や付いている拡張子が信用できない場合、shared-mime-infoを使うしかありません。

なお、どちらも pure ruby であり、また gem を使って簡単にインストールすることが出来ます。

gem install mime-types
gem install shared-mime-info

以下に簡単に使い方をまとめておきます。

MIME::Typesライブラリ

クラスMIME::Typesのクラスメソッド type_for を使って判別を行ないますが、返り値がMIME::Typeオブジェクトのリストであることに注意しましょう。

require 'mime/types'
path = '/home/keita/test.png'

MIME::Types.type_for(path)[0].to_s # => "image/png"

なおMIME::Typeクラスには encoding, binary?, ascii?, simplified などの微妙に便利そうなメソッドが用意されています。また新たな型を簡単に追加できますので、場合によっては便利だと思います。

shared-mime-infoライブラリ

クラスMIMEのクラスメソッド check/check_globs/check_magics を用いて判別を行ないます。返り値は MIME::Type オブジェクトです。

require 'shared-mime-info'
path = '/home/keita/test.png'

MIME.check(path) # ファイル名かファイル内容から判別する
MIME.check_globs(path) # ファイル名から
MIME.check_magics(path) # ファイル内容から

MIME::Typeオブジェクトにはメソッド comment がありますが、これは shared-mime-infoデータベースに登録されている説明文を返します。この説明文は各国語に訳されているので非常に便利そうです。

判別速度の比較

簡単に判別速度を比較しておくことにします。以下のスクリプトをつかって計測してみます。

require 'benchmark'

require 'rubygems'
require 'mime/types'
M1 = MIME
require 'shared-mime-info'
M2 = MIME

$path = "/home/keita/test.png"
$n = 1000

Benchmark.bm do |job|
  job.report {$n.times do; M1::Types.type_for($path); end}
  job.report {$n.times do; M2.check($path); end}
  job.report {$n.times do; M2.check_globs($path); end}
  job.report {$n.times do; M2.check_magics($path); end}
end

私の環境での実行結果は以下のようになりました。

      user     system      total        real
  0.010000   0.000000   0.010000 (  0.016317)
  1.700000   0.220000   1.920000 (  2.036679)
  1.440000   0.230000   1.670000 (  1.897744)
  2.790000   0.430000   3.220000 (  3.521380)

よって、MIME::Typesライブラリの方が圧倒的に速いようです。

結論

ファイルに対するMIME型の自動判別を行なう場合、ファイル名に拡張子が付いていることが保証できるのならばMIME::Typesライブラリを、そうでなければshared-mime-infoライブラリを使いましょう。一般的にはshared-mime-infoを使っておけばあらゆる状況に対応できると思いますので、私はshared-mime-infoをオススメします。ただし判別速度を重視する場合にはMIME::Typesを使うべきかも知れません。