Bestimmen Sie den Dateityp in Ruby


74

Wie bestimmt man zuverlässig den Dateityp? Eine Analyse der Dateierweiterung ist nicht akzeptabel. Es muss ein rubyeskes Tool geben, das dem Befehl UNIX file (1) ähnelt.

Dies betrifft MIME oder den Inhaltstyp, nicht Dateisystemklassifizierungen wie Verzeichnis, Datei oder Socket.

Antworten:


58

Es gibt eine Rubinbindung, die genau libmagicdas tut, was Sie brauchen. Es ist als Edelstein namens Ruby-Filemagic erhältlich :

gem install ruby-filemagic

Benötigen libmagic-dev.

Die Dokumentation scheint etwas dünn zu sein, aber dies sollte Ihnen den Einstieg erleichtern:

$ 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> 

Laut grub.ath.cx/filemagic/CHANGELOG scheint dieses Juwel nicht aktiv gepflegt zu werden.
Lars Haugseth

23
Ich freue mich, berichten zu können, dass dieses Juwel wieder aktiv gepflegt wird. Github.com/blackwinter/ruby-filemagic
Martin Carpenter

Funktioniert auch unter Windows.
Chris Finne

3
Auch dieses Juwel scheint nicht aktiv gepflegt zu werden. Es ist auf Github mit "nicht gepflegt" und "adoptiere mich" markiert .
Tanius

35

Wenn Sie sich auf einem Unix-Computer befinden, versuchen Sie Folgendes:

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

Mir sind keine reinen Ruby-Lösungen bekannt, die so zuverlässig funktionieren wie "Datei".

Bearbeitet, um hinzuzufügen: Je nachdem, welches Betriebssystem Sie ausführen, müssen Sie möglicherweise 'i' anstelle von 'I' verwenden, damit die Datei einen MIME-Typ zurückgibt.


18
Versuchen Sie, popen zu verwenden, um böse Hackery zu verhindern:IO.popen(["file", "--brief", "--mime-type", path], in: :close, err: :close).read.chomp
sj26

Ja, das oder das cocaineJuwel.
Maletor

8
@ sj26 Jedes Mal popen, wenn ich anrufe , erhalte ich einen Zombie-Prozess, da das E / A-Objekt nicht geschlossen ist. Um das zu beheben, verwenden Sie einen Block:IO.popen(["file", "--brief", "--mime-type", path], in: :close, err: :close) { |io| io.read.chomp }
Andrew

1
@Pete Das Interpolieren potenziell vom Benutzer bereitgestellter Inhalte in eine Befehlszeichenfolge wie Backticks ist eine potenzielle Sicherheitslücke. Die Verwendung von popen mit einer Reihe von Argumenten verhindert diese Exploit-Kategorie. :-)
sj26

1
Hervorragender Punkt über Zombies! IO.popen(["file", "--brief", "--mime-type", path], &:read).chompfunktioniert auch.
Sj26

14

Ich fand das Beschießen am zuverlässigsten. Aus Gründen der Kompatibilität unter Mac OS X und Ubuntu Linux habe ich Folgendes verwendet:

file --mime -b myvideo.mp4
Video / mp4; Zeichensatz = binär

Ubuntu druckt auch Video-Codec-Informationen, wenn dies möglich ist, was ziemlich cool ist:

file -b myvideo.mp4
ISO Media, MPEG v4-System, Version 2


6
sollte file -b --mime-type myvideo.mp4für die Webnutzung sein
Yam Marcovic

8

Sie können diese zuverlässige Methode basierend auf dem magischen Header der Datei verwenden:

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

1
Sie müssen auch nach "\ xff \ xd8 \ xff \ xdb" als JPEG-Signatur suchen.
Richard Fairhurst

6

Wenn Sie die File-Klasse verwenden, können Sie sie basierend auf der Antwort von @ PatrickRichie mit den folgenden Funktionen erweitern:

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

Wenn Sie Ruby on Rails verwenden, können Sie dies in config / initializers / file.rb ablegen und im gesamten Projekt verfügbar haben.


3

Dies wurde als Kommentar zu dieser Antwort hinzugefügt , sollte aber eigentlich eine eigene Antwort sein:

path = # path to your file

IO.popen(
  ["file", "--brief", "--mime-type", path],
  in: :close, err: :close
) { |io| io.read.chomp }

Ich kann bestätigen, dass es bei mir funktioniert hat.


1
Dies funktioniert perfekt mit dem zusätzlichen Bonus, dass Sie keinen weiteren Edelstein hinzufügen und pflegen müssen.
Steven Hirlston

2

Sie können Shared-Mime ausprobieren (gem install shared-mime-info). Erfordert die Verwendung der Freedesktop Shared-Mime-Info-Bibliothek, führt jedoch sowohl Dateinamen- / Erweiterungsprüfungen als auch "magische" Prüfungen durch. Ich habe gerade versucht, sie selbst zu testen, aber ich habe keine Freedesktop Shared-Mime-Informationen Datenbank installiert und muss leider "echte Arbeit" leisten, aber es könnte das sein, wonach Sie suchen.


2

Für diejenigen, die mit der Suchmaschine hierher gekommen sind, besteht ein moderner Ansatz, um den MimeType in reinem Rubin zu finden, darin, das mimemagische Juwel zu verwenden.

require 'mimemagic'

MimeMagic.by_magic(File.open('tux.jpg')).type # => "image/jpeg" 

Wenn Sie der Meinung sind, dass es sicher ist, nur die Dateierweiterung zu verwenden, können Sie das Juwel mime-types verwenden :

MIME::Types.type_for('tux.jpg') => [#<MIME::Type: image/jpeg>]


1

Ich habe kürzlich mimetype-fu gefunden .

Es scheint die einfachste und zuverlässigste Lösung zu sein, um den MIME-Typ einer Datei zu erhalten.

Die einzige Einschränkung ist, dass auf einem Windows-Computer nur die Dateierweiterung verwendet wird, während es auf * Nix-basierten Systemen hervorragend funktioniert.




-2

Sie können MIME :: Types for Ruby ausprobieren .

Diese Bibliothek ermöglicht die Identifizierung des wahrscheinlichen MIME-Inhaltstyps einer Datei. Die Identifizierung des MIME-Inhaltstyps basiert auf den Dateinamenerweiterungen einer Datei.


6
Aus Readme.txt: "Die Identifizierung des MIME-Inhaltstyps basiert auf den Dateinamenerweiterungen einer Datei." OP forderte ausdrücklich eine Methode an, die auf einer Inhaltsanalyse und nicht auf einer Dateinamenerweiterung basiert.
Martin Carpenter
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.