Определить тип файла в Ruby
Как надежно определить тип файла? Анализ расширений файлов недопустим. Должен быть инструмент rubyesque, похожий на команду UNIX file(1)?
Это касается MIME или типа контента, а не классификации файловой системы, такой как каталог, файл или сокет.
12 ответов
Существует рубиновая привязка к libmagic
это делает то, что вам нужно. Он доступен как гем под названием ruby-filemagic:
gem install ruby-filemagic
требовать libmagic-dev
,
Документация кажется немного тонкой, но с этого следует начать:
$ irb
irb(main):001:0> require 'filemagic'
=> true
irb(main):002:0> fm = FileMagic.new
=> #<FileMagic:0x7fd4afb0>
irb(main):003:0> fm.file('foo.zip')
=> "Zip archive data, at least v2.0 to extract"
irb(main):004:0>
Если вы работаете на Unix-машине, попробуйте это:
mimetype = `file -Ib #{path}`.gsub(/\n/,"")
Я не знаю ни одного чистого решения Ruby, которое работает так же надежно, как "файл".
Отредактировано, чтобы добавить: в зависимости от того, какую операционную систему вы используете, вам может понадобиться использовать "i" вместо "I", чтобы получить файл, возвращающий mime-тип.
Я считаю обстрелы самыми надежными. Для совместимости на Mac OS X и Ubuntu Linux я использовал:
file --mime -b myvideo.mp4
видео /mp4; кодировка = двоичная
Ubuntu также печатает информацию о видеокодеках, если это возможно, что довольно круто:
file -b myvideo.mp4
ISO Media, система MPEG v4, версия 2
Это было добавлено как комментарий к этому ответу, но на самом деле это должен быть отдельный ответ:
path = # path to your file
IO.popen(
["file", "--brief", "--mime-type", path],
in: :close, err: :close
) { |io| io.read.chomp }
Могу подтвердить, что у меня это сработало.
Вы можете использовать этот надежный метод на основе магического заголовка файла:
def get_image_extension(local_file_path)
png = Regexp.new("\x89PNG".force_encoding("binary"))
jpg = Regexp.new("\xff\xd8\xff\xe0\x00\x10JFIF".force_encoding("binary"))
jpg2 = Regexp.new("\xff\xd8\xff\xe1(.*){2}Exif".force_encoding("binary"))
case IO.read(local_file_path, 10)
when /^GIF8/
'gif'
when /^#{png}/
'png'
when /^#{jpg}/
'jpg'
when /^#{jpg2}/
'jpg'
else
mime_type = `file #{local_file_path} --mime-type`.gsub("\n", '') # Works on linux and mac
raise UnprocessableEntity, "unknown file type" if !mime_type
mime_type.split(':')[1].split('/')[1].gsub('x-', '').gsub(/jpeg/, 'jpg').gsub(/text/, 'txt').gsub(/x-/, '')
end
end
Если вы используете класс File, вы можете дополнить его следующими функциями на основе ответа @PatrickRichie:
class File
def mime_type
`file --brief --mime-type #{self.path}`.strip
end
def charset
`file --brief --mime #{self.path}`.split(';').second.split('=').second.strip
end
end
И, если вы используете Ruby on Rails, вы можете оставить это в config/initializers/file.rb и сделать его доступным для всего вашего проекта.
Для тех, кто пришел сюда с помощью поисковой системы, современный подход к поиску MimeType в чистом рубине - это использование мимемагического камня.
require 'mimemagic'
MimeMagic.by_magic(File.open('tux.jpg')).type # => "image/jpeg"
Если вы чувствуете, что безопасно использовать только расширение файла, тогда вы можете использовать гем mime-types:
MIME::Types.type_for('tux.jpg') => [#<MIME::Type: image/jpeg>]
Вы можете попробовать shared-mime (gem install shared-mime-info). Требует использования библиотеки shared-mime-info Freedesktop, но выполняет как проверки имени файла / расширения, так и проверки "магии"... я пытался сделать это сейчас, но у меня нет freedesktop shared-mime-info База данных установлена и, к сожалению, должна выполнять "реальную работу", но это может быть то, что вы ищете.
Я недавно нашел миметип-фу.
Кажется, это самое простое и надежное решение для получения файла MIME-типа.
Единственное предостережение в том, что на компьютере с Windows он использует только расширение файла, тогда как в системах на базе *Nix он прекрасно работает.
Чистое решение Ruby, использующее магические байты и возвращающее символ для соответствующего типа:
https://github.com/SixArm/sixarm_ruby_magic_number_type
Я написал это, так что если у вас есть предложения, дайте мне знать.
Лучшее, что я нашел до сих пор:
Вы можете попробовать MIME::Types для Ruby.
Эта библиотека позволяет определить вероятный тип содержимого файла MIME. Идентификация типа содержимого MIME основана на расширениях имени файла.