Jak dokładnie określić dane mime z pliku?

Dodaję pewną funkcjonalność do programu, dzięki czemu mogę dokładnie określić typ plików, odczytując dane MIME. Wypróbowałem już kilka metod:

Metoda 1:

javax.activation.FileDataSource

FileDataSource ds = new FileDataSource("~\\Downloads\\777135_new.xls");  
String contentType = ds.getContentType();  
System.out.println("The MIME type of the file is: " + contentType);

//output = The MIME type of the file is: application/octet-stream

Metoda 2:

import net.sf.jmimemagic.*;

try
{
    RandomAccessFile f = new RandomAccessFile("~\\Downloads\\777135_new.xls", "r");
    byte[] fileBytes = new byte[(int)f.length()];
    f.read(fileBytes);
    MagicMatch match = Magic.getMagicMatch(fileBytes);
    System.out.println("The Mime type is: " + match.getMimeType());
}
catch(Exception e)
{
    System.out.println(e);
}

//output = The Mime type is: application/msword

Metoda 3:

import eu.medsea.mimeutil.*;

MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
File f = new File ("~\\Downloads\\777135_new.xls");
Collection<?> mimeTypes = MimeUtil.getMimeTypes(f);
String mimeType = MimeUtil.getFirstMimeType(mimeTypes.toString()).toString();
String subMimeType = MimeUtil.getSubType(mimeTypes.toString());
System.out.println("The Mime type is: " + mimeTypes + ", " + mimeType + ", " + subMimeType);

//output = The Mime type is: application/msword, application/msword, msword

Znalazłem te trzy metody na http://www.rgagnon.com/javadetails/java-0487.html . jednak mój problem polega na tym, że plik, na którym testuję te metody, jest taki, który stworzyłem i Wiem, że jest to plik Excela, ale nadal wszystkie trzy metody niepoprawnie odbierają Typ jako msword z wyjątkiem pierwszej metody, która moim zdaniem jest spowodowana ograniczoną liczbą typów plików w wbudowanej mapie plików, której używa metoda.

Rozejrzałem się i niektórzy mówią, że to dlatego, że sposób, w jaki offset jest wykrywany w plikach, a więc typ zawartości jest nieprawidłowo odbierany, jak wskazano w tej wiki na wykrywaniu typów plików w PHP. Niestety wiki następnie używa rozszerzenia do określenia Typ pliku, który nie jest tym, co chcę zrobić, ponieważ jest zawodny.

Czy ktoś może wskazać mi drogę do metody, która poprawnie wykrywa typy plików w Javie?

Pozdrawiam, Alexei Blue.

Edit: wygląda na to, że nie ma na to konkretnego rozwiązania, jak powiedział @IronMensan w komentarzu poniżej. Znalazłem ten naprawdę interesujący artykuł badawczy , który stosuje uczenie maszynowe na kilka sposobów, aby pomóc w tym problemie, ale nie wydaje się, aby był pełny dowód odpowiedz. Myślę, że moim najlepszym rozwiązaniem będzie próba przekazania pliku do czytnika plików excel i wyłapania nieprawidłowych WYJĄTKÓW w formacie.

Author: Alexei Blue, 2011-12-13

3 answers

Jak wspomniano w komentarzach, ponieważ jest tak wiele możliwych typów plików, że można trafić i przegapić wszystkie możliwe pliki, ale prawdopodobnie wiesz, z jakimi typami plików Zwykle będziesz miał do czynienia. Ta doskonała lista magicznych liczb pomogła mi ostatnio wykryć konkretne formaty pakietu office, o których wspomniałeś (wyszukaj Microsoft Office), a zobaczysz, że typy plików MS office mają określony Podtyp (który jest dalej w pliku) i pozwala na pracę dokładnie jaki typ pliku masz. Wiele nowych formatów, takich jak ODT, DOCX, OOXML itp., używa pliku ZIP do przechowywania danych, więc może być konieczne najpierw wykrycie zip, a następnie wyszukanie szczegółów.

 3
Author: Paul Jowett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-16 01:11:41

Jak dotąd, najdokładniejszym narzędziem, jakie znalazłem do określenia typu MIME pliku jest Apache Tika . Jest to niewielka modyfikacja tego, czego obecnie używam (z Tika w wersji 1.0)

import org.apache.tika.detect.DefaultDetector;
import org.apache.tika.detect.Detector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MimeTypes;

private static final Detector DETECTOR = new DefaultDetector(
        MimeTypes.getDefaultMimeTypes());

public static String detectMimeType(final File file) throws IOException {
    TikaInputStream tikaIS = null;
    try {
        tikaIS = TikaInputStream.get(file);

        /*
         * You might not want to provide the file's name. If you provide an Excel
         * document with a .xls extension, it will get it correct right away; but
         * if you provide an Excel document with .doc extension, it will guess it
         * to be a Word document
         */
        final Metadata metadata = new Metadata();
        // metadata.set(Metadata.RESOURCE_NAME_KEY, file.getName());

        return DETECTOR.detect(tikaIS, metadata).toString();
    } finally {
        if (tikaIS != null) {
            tikaIS.close();
        }
    }
}

Ponieważ Tika będzie używać magicznych liczb, ale także patrzeć na zawartość plików, gdy nie jesteś pewien, proces może być trochę kosztowny (zajęło 3.268 sekund dla mojego komputera, aby zbadać 15 plików).

Nie popełniaj tego samego błędu, co ja na początku. Jeśli otrzymasz tika-core słoik, powinieneś Pobierz również tika-parsery JAR. Jeśli nie otrzymasz tika-parserów nie otrzymasz żadnych WYJĄTKÓW, po prostu nie otrzymasz dokładnie typu MIME, więc naprawdę ważne jest, aby go uwzględnić.

Alternatywą jest uzyskanie tika-app JAR, który zawiera tika-core, tika-parsery i wszystkie zależności (jest ich dużo: poi, poi-ooxml, xmlbeans, commons-compress, żeby wymienić tylko kilka).

 28
Author: rodrigo.garcia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-12 10:33:34

Nie jestem do końca pewien, jak dokładne to jest, ale to działało dla mnie w prostych przypadkach.

    FileNameMap fileNameMap = URLConnection.getFileNameMap();
    String type = fileNameMap.getContentTypeFor(filePath);
 0
Author: EpicPandaForce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-04 11:09:22