Як надійно визначити тип файлу? Аналіз розширення файлу неприйнятний. Повинен бути рубієнний інструмент, подібний до команди файлу UNIX (1)?
Це стосується MIME або типу вмісту, а не класифікацій файлової системи, таких як каталог, файл або сокет.
Як надійно визначити тип файлу? Аналіз розширення файлу неприйнятний. Повинен бути рубієнний інструмент, подібний до команди файлу UNIX (1)?
Це стосується MIME або типу вмісту, а не класифікацій файлової системи, таких як каталог, файл або сокет.
Відповіді:
Існує рубінова прив’язка, 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.
IO.popen(["file", "--brief", "--mime-type", path], in: :close, err: :close).read.chomp
cocaine
самоцвіт.
popen
, я отримую процес зомбі, оскільки об'єкт вводу-виводу не закритий. Щоб це виправити, використовуйте блок:IO.popen(["file", "--brief", "--mime-type", path], in: :close, err: :close) { |io| io.read.chomp }
IO.popen(["file", "--brief", "--mime-type", path], &:read).chomp
працює теж.
Я знайшов обстріл найнадійнішим. Для сумісності як на Mac OS X, так і на Ubuntu Linux я використовував:
file --mime -b myvideo.mp4
відео / mp4; charset = двійковий
Ubuntu також друкує інформацію про відеокодек, якщо може, що є дуже круто:
file -b myvideo.mp4
ISO Media, система MPEG v4, версія 2
file -b --mime-type myvideo.mp4
для користування Інтернетом
Ви можете використовувати цю надійну основу методів на магічному заголовку файлу:
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 і доступне у вашому проекті.
Це було додано як коментар до цієї відповіді, але насправді має бути власною відповіддю:
path = # path to your file
IO.popen(
["file", "--brief", "--mime-type", path],
in: :close, err: :close
) { |io| io.read.chomp }
Я можу підтвердити, що це спрацювало для мене.
Ви можете спробувати shared-mime (gem install shared-mime-info). Потрібне використання бібліотеки спільної mime-інформації Freedesktop, але робить як перевірку імені файлу / розширення, так і перевірку "магії" ... спробував дати йому кружлятись зараз, але у мене немає freedesktop shared-mime-info база даних встановлена і повинна виконувати "справжню роботу", на жаль, але це може бути те, що ви шукаєте.
Для тих, хто прийшов сюди за допомогою пошукової системи, сучасний підхід до пошуку MimeType в чистому рубіні - це використання мімемагічного каменя.
require 'mimemagic'
MimeMagic.by_magic(File.open('tux.jpg')).type # => "image/jpeg"
Якщо ви вважаєте, що безпечно використовувати лише розширення файлу, тоді ви можете використовувати самоцвіт mime-типів :
MIME::Types.type_for('tux.jpg') => [#<MIME::Type: image/jpeg>]
Чисте рішення Ruby з використанням магічних байтів і повернення символу для відповідного типу:
https://github.com/SixArm/sixarm_ruby_magic_number_type
Я це написав, тож якщо у вас є пропозиції, повідомте мене.
Нещодавно я знайшов mimetype-fu .
Здається, це найпростіше надійне рішення для отримання типу MIME файлу.
Єдине застереження полягає в тому, що на машині Windows він використовує лише розширення файлу, тоді як у системах на базі * Nix це чудово працює.
Найкраще, що я знайшов на даний момент:
Рубіновий самоцвіт добре. mime-типи для рубіну
Ви можете спробувати MIME :: Types для Ruby .
Ця бібліотека дозволяє ідентифікувати ймовірний тип вмісту файлу MIME. Ідентифікація типу вмісту MIME базується на розширеннях імен файлів.