2008-09-09 4 views
65

Как один достоверно определить тип файла? Анализ расширения файлов неприемлем. Должен быть рубиновый инструмент, похожий на команду UNIX file (1)?Определить тип файла в Ruby

Это относится к типу MIME или типу контента, а не к классификациям файловой системы, таким как каталог, файл или сокет.

ответ

-2

Вы можете дать MIME::Types for Ruby.

Эта библиотека позволяет идентифицировать возможный тип содержимого MIME файла. Идентификация типа содержимого MIME основана на расширениях файлов.

+6

Из файла Readme.txt: «Идентификация типа содержимого MIME основана на расширении имени файла». OP явно запросил метод, основанный на анализе контента, а не на расширении имени файла. – 2009-05-23 14:37:35

33

Если вы на машине Unix, попробуйте следующее:

mimetype = `file -Ib #{path}`.gsub(/\n/,"") 

Я не знаю ни чистых решений Ruby, которые работают так же надежно, как «файл».

Отредактировано для добавления: в зависимости от того, какая ОС вы используете, вам может потребоваться использовать «i» вместо «I», чтобы получить файл для возврата типа mime.

+16

Чтобы избежать неприятного хакера, попробуйте использовать popen: `IO.popen ([" file "," --brief "," --mime-type ", path], в:: close, err:: close) .read. chomp` – sj26 2012-05-22 02:11:59

+0

Yup, это или «кокаиновый» драгоценный камень. – maletor 2014-02-10 21:44:48

+6

@ sj26 Каждый раз, когда я называю «popen», я получаю зомби-процесс, потому что объект IO не закрыт. Чтобы исправить это, используйте блок: `IO.popen ([" file "," --brief "," --mime-type ", path], в:: close, err:: close) {| io | io.read.chomp} ` – Andrew 2014-04-17 21:31:41

2

Вы можете дать shared-mime попытку (gem install shared-mime-info). Требуется использование библиотеки share-mime-info Freedesktop, но выполняет как проверки имени файла, так и проверки «волшебства» ... попробовал дать ему вихрь сейчас, но у меня нет версии freedesktop shared-mime-info база данных установлена ​​и должна выполнять «настоящую работу», к сожалению, но это может быть то, что вы ищете.

57

Существует рубиновая привязка к 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> 
1

Я недавно нашел mimetype-fu.

Это, пожалуй, самое простое надежное решение для получения типа MIME файла.

Единственное предостережение заключается в том, что на машине с Windows он использует только расширение файла, тогда как на системах на основе Nix он отлично работает.

12

Я нашел обстрел, чтобы быть самым надежным.Для совместимости на обоих Mac OS X и Ubuntu Linux Я использовал:

file --mime -b myvideo.mp4
видео/mp4; кодировка = двоичный

Ubuntu также печатает информацию видеокодек, если он может что довольно круто:

file -b myvideo.mp4
ISO Медиа, система v4 MPEG, версия 2

8

Вы можете использовать этот надежный метод базы на волшебном заголовке файла:

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 
4

Если вы используете класс 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 и иметь доступный во всем своем проекте.